3868993738 objective

225
kurz & gut O’Reillys Taschenb ibliothek Objective-C

Upload: jaime-avendano

Post on 04-Jun-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 1/224

kurz & gut 

O’REILLY

O’Reillys Taschenbibliothek 

 Lars Schulten

Objective-C

Page 2: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 2/224

Page 3: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 3/224

Page 4: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 4/224

Die Informationen in diesem Buch wurden mit größter Sorgfalt erarbeitet. Dennochkönnen Fehler nicht vollständig ausgeschlossen werden. Verlag, Autoren undÜbersetzer übernehmen keine juristische Verantwortung oder irgendeine Haftungfür eventuell verbliebene Fehler und deren Folgen.

Alle Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutztund sind möglicherweise eingetragene Warenzeichen. Der Verlag richtet sich imWesentlichen nach den Schreibweisen der Hersteller. Das Werk einschließlich allerseiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlichder Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung undVerarbeitung in elektronischen Systemen.

Kommentare und Fragen können Sie gerne an uns richten:O’Reilly Verlag GmbH & Co. KG

Balthasarstr. 8150670 KölnE-Mail: [email protected]

Copyright der deutschen Ausgabe: 2013 O’Reilly Verlag GmbH & Co. KG1. Auflage 2013

Die Darstellung eines Steppenfuchses im Zusammenhang

mit dem Thema Objective-C ist ein Warenzeichen von O’Reilly Media, Inc.

Bibliografische Information Der Deutschen NationalbibliothekDie Deutsche Nationalbibliothek verzeichnet diese Publikation in derDeutschen Nationalbibliografie; detaillierte bibliografische Datensind im Internet über http://dnb.d-nb.de abrufbar.

Lektorat: Alexandra Follenius, KölnFachgutachten: Ingo Dellwig, Hannover

Korrektorat: Sibylle Feldmann, Düsseldorf Produktion: Andrea Miß, KölnUmschlaggestaltung: Ellie Volckhausen, Sebastopol & Michael Oreal, KölnSatz: Reemers Publishing Services GmbH, Krefeld, www.reemers.deDruck: fgb  freiburger graphische betriebe; www.fgb.de

ISBN: 978-3-86899-373-8

Dieses Buch ist auf 100% chlorfrei gebleichtem Papier gedruckt.

Page 5: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 5/224

Inhalt

Einfu hrung .....................................................................   1

1   Grundlagen ...............................................................   5Ein erstes Beispiel ..........................................................   5

Code schreiben und kompilieren ..........................................   6

Headerdateien..............................................................   8

Frameworks ................................................................   9

2   Syntax 11Klassen und Objekte .......................................................   11

Nachrichten.................................................................   12

Compilerdirektiven .........................................................   13

Literaldeklarationen ........................................................   14

Blocks.......................................................................   18

Ein zweites Beispiel ........................................................   19

3   Objekte....................................................................   23Objektvariablen und Zeiger ................................................   23

Objekte erstellen ...........................................................   27

Mit Objekten interagieren .................................................   28

Objekte vergleichen ........................................................   29

Objekt-Enumeration........................................................   30

Objektindizierung ..........................................................   30

4   Klassen ....................................................................   33Klassendeklaration und -definition ........................................   33

Felder.......................................................................   35

Methoden ..................................................................   38

Eigenschaften...............................................................   47

| III

Page 6: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 6/224

Vererbung und Polymorphie...............................................   56

Typumwandlungen ........................................................   61

5   Kategorien und Klassenerweiterungen ..............................   63

Klassenerweiterungen......................................................   65

6   Protokolle.................................................................   67Ein Protokoll deklarieren...................................................   67

Protokolle implementieren ................................................   69

Optionale Methoden aufrufen .............................................   70

Protokolle als Referenztypen ..............................................   71

Informelle Protokolle.......................................................   71

7   Fehler und Ausnahmen.................................................   73Fehler.......................................................................   74

NSError-Referenz ...........................................................   76

Ausnahmen.................................................................   78

NSException-Referenz ......................................................   83

8   NSObject ..................................................................   85

9   Objektlebenszyklus......................................................   87Objekte erstellen ...........................................................   88

Objekte kopieren ...........................................................   95

Objektvernichtung..........................................................   99

10   Speicherverwaltung .....................................................   101Was Speicherverwaltung ist ...............................................   101

Speicherverwaltungstechnologien unter Objective-C......................   102

ARC (Automatic Reference Counting)......................................   104

MRC (Manuel Reference Counting) ........................................   110

11   Laufzeitinformationen..................................................   115Objektinformationen .......................................................   116

Klasseninformationen ......................................................   117

Funktionsinformationen....................................................   123

Protokollinformationen ....................................................   124

12   Messaging ................................................................   127Kompilierung ...............................................................   128

Selektoren ..................................................................   129

IV | Inhalt

Page 7: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 7/224

Implementierungen ........................................................   130

Selektoren dynamisch ausfuhren ..........................................   131

Implementierungen cachen ................................................   135

Dynamische Methodenimplementierung ..................................   137Nachrichtenweiterleitung ..................................................   139

13   Key/ Value-Coding .......................................................   143KVC-Konformitat ...........................................................   143

Schlusselbasierte Interaktion mit Objekten ................................   144

Schlusselpfade..............................................................   145

Virtuelle Schlussel ..........................................................   146

KVC-Validierung ............................................................   147

Schlusselpfadoperatoren ...................................................   148

14   Objektarchivierung ......................................................   151Sequenzielle und schlusselbasierte Archive  ...............................   153

Die NSCoding-Methoden implementieren .................................   153

Coder-Objekte ..............................................................   156

15   Blocks 159Blocks definieren ...........................................................   159

Blocks als Objekte ..........................................................   161

Zugriff auf den Kontext ....................................................   161

Lokale Variablen ...........................................................   165

Globale und kontextgebundene Blocks....................................   168

16   NSObject-Referenz.......................................................   173

17   Compilerdirektiven ......................................................   185

18   Alternative Plattformen ................................................   195Compiler....................................................................   196

Clang/LLVM ................................................................   196

Laufzeitumgebungen und Plattformen ....................................   197

19   Clang-Optionen ..........................................................   201

Index............................................................................   205

Inhalt | V

Page 8: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 8/224

Page 9: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 9/224

Einfu hrung

Objective-C ist  die  Programmiersprache der letzten Jahre. Die Be-liebtheit von Apples Plattformen, iOS und Mac OS X, sorgt dafür,dass die Sprache heute aktueller ist als je zuvor.   Objective-C – kurz & gut  ist ein kompaktes Handbuch zur ProgrammierspracheObjective-C. Es illustriert die grundlegenden Aspekte der Sprachemit kurzen Erklärungen, die von kleineren Beispielen aufgelockert

werden, und bietet einen Überblick über die wichtigsten Technolo-gien, Klassen, Nachrichten und Funktionen. Es richtet sich an alle,die bereits für andere Plattformen programmiert haben und sichnun in diese spannende Sprache einarbeiten wollen.

Sie sollten mit mindestens einer Sprache ver-traut sein, die eine C-artige Syntax nutzt. Ob-

 jective-C setzt auf C auf und nutzt viele Ele-mente seiner Syntax unverändert. Das heißt,elementare Syntaxformen, wie Schleifen undBedingungsanweisungen, sowie die elementa-ren C-Datentypen werden in diesem Buchnicht erläutert. Das bedeutet aber nicht, dassSie C selbst beherrschen müssen. Eine belie-bige an C angelehnte Programmiersprache mit

äquivalenten Sprachelementen, Java oder C#beispielsweise, reicht vollkommen aus. WennSie bislang nur mit dynamisch typisierten Spra-chen wie z. B. JavaScript gearbeitet haben,sollten Sie sich allerdings unbedingt mit stati-schen Typsystemen vertraut machen.

| 1

Page 10: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 10/224

Objective-CObjective-C ist ein C-Dialekt. Es bildet eine vollständige Ober-

menge zu C und bietet alles, was auch C bietet. Es besitzt diegleichen Syntaxstrukturen und -elemente, nutzt die gleichen Daten-typen und kann sogar auf die gleichen Bibliotheken zugreifen.Wenn Sie sich Objective-C von C her nähern, werden Ihnen alsoviele Dinge bekannt vorkommen. Sie könnten einem Objective-C-Compiler sogar Ihren alten C-Quellcode vorsetzen, und dieserwürde ihn anstandslos kompilieren.

Haben Sie keine Erfahrung mit C, müssen Sie sich zusätzlich zumeigentlichen Objective-C-Kern noch mit gewissen Aspekten von Causeinandersetzen, die bei der Arbeit mit Objective-C unumgäng-lich sind. Auf einige dieser Aspekte wie C-Zeiger werden wir (kurz)eingehen, da ansonsten ein Verständnis von Objective-C unmöglichist. Andere wie die diversen C-Datentypen und C-Syntaxstrukturenwerden wir hier nicht beschreiben, da wir davon ausgehen, dass Sie

bereits mit Sprachen wie Java, C# usw. gearbeitet haben, dieähnliche Features bieten. Sollte das nicht der Fall sein, müssen Siedie entsprechenden Informationen in einem geeigneten C-Buchnachschlagen.

Objective-C ist aber auch eine objektorientierte Programmierspra-che, die alle Features bietet, die Ihnen aus anderen objektorientier-

ten Programmiersprachen vertraut sein sollten: Objekte, Klassen,Schnittstellen, Vererbung, Polymorphie usw. Dazu erweitert es Cum die entsprechenden Strukturen und Syntaxformen: Compiler-direktiven, Syntaxstrukturen zur Definition von Klassen und ihrenElementen, Syntaxstrukturen zur Arbeit mit Klassen und ihrenElementen und einige neue Datentypen. Das Buch erläutert diewichtigsten Aspekte der objektorientierten Programmierung und

ihre spezifische Implementierung in Objective-C und geht dabeiauch explizit auf die Punkte ein, an denen sich die objektorientierteProgrammierung unter Objective-C von der in z. B. Java unterschei-det.

2 | Einführung

Page 11: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 11/224

Werkzeuge und PlattformenObjective-C ist eigentlich plattformunabhängig. Es gibt eine Reihe

von Compilern, die Objective-C-Code kompilieren können, undverschiedene Laufzeitumgebungen, die in Objective-C-Code einge-bunden werden können. In diesem Buch werden wir uns auf dieWerkzeuge und die Laufzeitumgebung für Apples Plattformen kon-zentrieren. Einen kurzen Überblick über andere verfügbare Werk-zeuge und Bibliotheken finden Sie in Kapitel 18,  Alternative Platt-

 formen. Da Apple die Sprache in den letzten Jahren umfassend

erweitert hat, kann es sein, dass diese die neuesten Sprach-Featuresnicht immer vollständig unterstützen.

Wir werden hier Objective-C in der Versionbehandeln, in der es von den Werkzeug- undBetriebssystemversionen unterstützt wird, dieaktuell waren, als dieses Buch geschriebenwurde: XCode 4.6 mit Clang 4.2 und LLVM3.2 sowie Mac OS X 10.8 und iOS 6. Das heißtauch, dass als Entwicklungsplattform ein Sys-tem erforderlich ist, auf dem mindestens OS X 10.7 (Lion) läuft, da die benötigten Versionenvon Xcode und Clang für frühere Betriebssys-temversionen nicht verfügbar sind.

Die BeispieleDie Beispiele sind eher knapp und nicht vollständig. In der Regeldienen sie nur der Illustration eines einzigen Problems und sinddeshalb so einfach wie möglich gehalten. Sie machen extensivenGebrauch von den neuesten Objective-C-Technologien und gehen,

soweit nicht anders vermerkt, davon aus, dass der Code mit ARC-Unterstützung kompiliert wird.

Die Beispiele | 3

Page 12: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 12/224

Page 13: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 13/224

Page 14: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 14/224

• Die Elemente, mit denen der Code operiert (Funktionen,Variablen usw.), haben stets einen Typ (int main(),  int argc

usw.).

• Anweisungsblöcke stehen in geschweiften Klammern.• Anweisungen werden mit einem Semikolon abgeschlossen.

Unbekannt könnten Ihnen die   #import-,   @autorealesepool- und@"…"-Konstruktionen sein, da das Objective-C-eigene Syntaxele-mente sind:

•   #import ist eine Objective-C-spezifische Präprozessordirektive,

die eine Headerdatei importiert.

•   @autoreleasepool ist eine Objective-C-Compilerdirektive.

•   @"…" definiert ein Objective-C-Stringliteral.

Die beiden   @-Formen werden in   Kapitel 2,   Syntax, ausführlichererläutert, #import im Abschnitt »Headerdateien« auf Seite 8.

NSLog()   ist eine Protokollierungsfunktion, die Nachrichten miteinem Zeitstempel versehen auf der Konsole ausgibt. Als erstesArgument erwartet sie ein Objective-C-Stringliteral. Das Stringlite-ral kann Formatangaben enthalten, die durch die nachfolgendenArgumente ersetzt werden, zum Beispiel:

NSLog(@"Das Leben ist %@", 1 > 0 ? @"schon" : @"be…");

Die Formatangabe  %@  formatiert ein Objective-C-Objekt, hier dasObjective-C-Stringobjekt, zu dem der Bedingungsausdruck aus-gewertet wird. Daneben unterstützt Objective-C die von der printf-Spezifikation definierten Formatzeichen.

Code schreiben und kompilieren

Unter Mac OS X haben Sie zwei Möglichkeiten, Objective-C-Codezu schreiben und zu erstellen. Sie können beides mit Apples IDE

 Xcode tun, oder Sie schreiben mit einem Programm Ihrer Wahl understellen mit Apples Kommandozeilenwerkzeugen.

 Xcode erhalten Sie im Mac App Store oder auf Apples Entwick-lerseiten unter  https://developer.apple.com/downloads/ . Die Kom-mandozeilenwerkzeuge können Sie aus Xcode (unter

6 | Kapitel 1: Grundlagen

Page 15: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 15/224

Preferences…/Downloads/Components/Command Line Tools) instal-lieren oder separat von Apples Entwicklerseiten für Ihr Systemherunterladen. Beachten Sie, dass Downloads und viele andere

Ressourcen nur Mitgliedern in Apples Entwicklerprogramm zu-gänglich sind. Eine kostenlose Mitgliedschaft genügt.

 Xcode

Der Code in diesem Beispiel ist eine nur minimal angepassteFassung des Inhalts der main.m-Datei, die die Xcode-Projektvorlage

für ein Kommandozeilenprojekt generiert. Sie können diesen Codekompilieren und ausführen, indem Sie in Xcode ein neues Kom-mandozeilenprojekt anlegen (File/New/Project/OS X/Application/ Command Line Tool), dann nach Belieben vor dem Ausführen linksim Projektnavigator main.m anwählen und im Editor die Änderun-gen vornehmen. Oder Sie klicken gleich auf den  Run-Button, denSie in Abbildung Abbildung 1-1  oben links sehen, um die Kom-

pilation und Ausführung des Programms anzustoßen.

 Abbildung 1-1: Apples IDE, Xcode

Code schreiben und kompilieren | 7

Page 16: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 16/224

Kommandozeilenkompilation

Alternativ können Sie die Datei über die Kommandozeile kompilie-ren und ausführen. Geben Sie den Code in einen Texteditor IhrerWahl ein und speichern Sie die Datei unter einem Namen, der dieDateinamenserweiterung  .m  trägt, z.B.  welt.m. Das ist die üblicheDateinamenserweiterung für Objective-C-Dateien. Öffnen Sie dieTerminalanwendung und navigieren Sie in das Verzeichnis, in demSie Ihre Datei gespeichert haben. Geben Sie dann den folgendenBefehl ein (vorausgesetzt, Sie haben den gleichen Namen gewähltwie wir), um den Code zu kompilieren:

clang -fobjc-arc -framework Foundation -o Welt welt.m

clang ist Apples »Objective-C-Compiler«. Der Kommandozeilenschal-ter -fobjc-arc fordert Automatic Reference Counting  (siehe Kapitel 10,Speicherverwaltung ) an, -framework gibt die Frameworks an, gegen diegelinkt werden soll, -o den Namen der Ausgabedatei. Das Kompilatkönnen Sie einfach mit folgender Anweisung ausführen:

./Welt

HeaderdateienHeader enthalten Deklarationen (von Klassen und Funktionen bei-spielsweise) und   Definitionen   (von Typen und Makros). Es sind

echte physische Dateien, die üblicherweise die Dateinamenserwei-terung  .h tragen. Sie werden in Codedateien eingelesen, um die inihnen enthaltenen Deklarationen und Definitionen in diesem Codeverfügbar zu machen. Das Codebeispiel importiert den HeaderFoundation/Foundation.h, damit der Compiler weiß, wie er mit denbeiden @…-Konstrukten umzugehen hat.

Eigene Headerdateien schreiben Sie bei Objective-C in der Regel,um Klassen und ihre Schnittstellen zu deklarieren (diesen Aspektwerden wir uns im Kapitel 4, Klassen, ansehen).

Header importieren

#import ist eine Objective-C-spezifische Präprozessordirektive zumImportieren von Headerdateien. Der Unterschied zum in C üblichen

8 | Kapitel 1: Grundlagen

Page 17: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 17/224

#include   ist, dass   #import   sicherstellt, dass Header nur einmalimportiert werden. Anders als Javas import oder C#s  using macht#import   nicht Namen bekannt, sondern liest Deklarationen und

eventuell auch Definitionen ein.#import kann auf zweierlei Weise verwendet werden: zum Importsystemweiter Headerdateien und zum Import anwendungsspezi-fischer Headerdateien:

•   #import <…> importiert einen Systemheader.

•   #import "…" importiert einen anwendungsspezifischen Header.

Zwischen den spitzen Klammern bzw. Anführungszeichen steht derName bzw. Pfad zu einer Headerdatei. Die verwendete Form steu-ert, wo nach der entsprechenden Datei gesucht wird, wenn derName kein absoluter Pfad ist. Bei der ersten Form wird in einer(über Compilerschalter und Umgebungsvariablen erweiterbaren)Liste von Standardverzeichnissen gesucht. Bei der zweiten Formwird zuvor noch im aktuellen Verzeichnis gesucht.

Üblicherweise gibt es zu jeder Codedatei, deren Definitionen in ande-ren Codedateien genutzt werden sollten, eine eigene Headerdatei.Daneben gibt es übergeordnete Header, sogenannte Umbrella-Header ,die viele in Zusammenhang stehende Header importieren und sogemeinsam importierbar machen. Der in unserem Beispiel verwendeteFoundation.h-Header ist der Umbrella-Header für das   Foundation-

Framework, das das Fundament der Cocoa-Objective-C-API bildet.

FrameworksUnter OS X und iOS werden Programmbibliotheken und andereRessourcen zu sogenannten Frameworks gebündelt. Diese werdenüblicherweise in  /System/Library/Frameworks und  /Library/Frame-

works gespeichert und stehen allen Anwendungen zur Verfügung.

Frameworks können unter anderem Headerdateien mit den Dekla-rationen für die Features enthalten, die sie bereitstellen. Ein Frame-work kann mehrere Headerdateien enthalten. Folgendermaßen bin-den Sie einen Header aus einem Framework ein:

#import <Framework/Header.h>

Frameworks | 9

Page 18: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 18/224

Der  Foundation/Foundation.h-Header, den unser Programm nutzt,ist ein Beispiel für einen solchen Framework-Header. Foundation istdas Framework,   Foundation.h   der Name der Headerdatei im

Framework. Die Headerangaben mit #import werden vom Compilerzur entsprechenden Ressource im Framework-Bundle   aufgelöst.Das heißt, dass der »Pfad« in der Headerangabe nicht dem tatsäch-lichen Dateipfad der Headerdatei entsprechen muss.

Der Foundation.h-Header ist der Umbrella-Header  für das Founda-tion-Framework. Ein Umbrella-Header ist ein Metaheader, der(meist) keine eigenen Deklarationen enthält, sondern die Header

für die verschiedenen Elemente eines Frameworks zusammenfasst.Wenn Sie eine Komponente eines Frameworks nutzen, sollten Sie inder Regel einen solchen übergeordneten Header verwenden, nichtdie Header für einzelne Komponenten.

Bei der Kommandozeilenkompilation geben Sie Frameworks, gegendie gelinkt werden soll, mit dem Schalter -framework an.

Wenn Sie Xcode nutzen, werden die Frameworks, die standard-mäßig für eine bestimmte Art von Anwendung genutzt werden,automatisch eingebunden. Müssen Sie zusätzliche Frameworks ein-binden, können Sie das für das jeweilige Build-Target im   LinkBinary With Libraries-Abschnitt der Registerkarte Build Phases tun,den Sie in der Abbildung Abbildung 1-2 sehen:

 Abbildung 1-2: Frameworks einbinden

10 | Kapitel 1: Grundlagen

Page 19: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 19/224

KAPITEL 2

Syntax

Objective-C erweitert C um eine Reihe von Syntaxstrukturen undKonzepten zur Unterstützung seiner dynamischen Variante derobjektorientierten Programmierung. Dieser Abschnitt stellt sie kurzvor, damit Sie den Beispielen in den nachfolgenden Teilen desBuchs folgen können. Komplexere Elemente wie Objekte undKlassen werden an anderer Stelle noch ausführlicher betrachtet.

Klassen und ObjekteObjective-C unterstützt alle C-Datentypen, elementare (z. B. imersten Beispiel oben char und  int) wie komplexe (z. B. Structs oderArrays). Daneben integriert es Strukturen zur Darstellung vonKlassen  und  Objekten. Klassen sind Anleitungen für den Aufbau

von  Gegenständen, Objekte sind die konkreten  Gegenstände, mitdenen Objective-C-Code arbeitet.

Objective-C-Objekte referenzieren Sie in Ihrem Code über Variablen,die Zeiger auf einen Wert des entsprechenden Typs, d. h. der Klasse,sind, oder den generischen Objekttyp id haben, zum Beispiel:

NSString *string = @"Kansas";

oder:

id objekt = @"Kaninchenbau";

Objekte können mit Literalausdrücken (siehe Abschnitt »Literalde-klarationen« auf Seite 14) definiert, von anderen Objekten geliefertoder mithilfe von Klassen konstruiert werden. Ausführlicher behan-deln wir Objekte und Klassen in den Kapiteln 3 und 4.

| 11

Page 20: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 20/224

NachrichtenDie Interaktion mit Objekten und Klassen erfolgt über Nachrichten.

Sie senden einem Empfänger  (einer Klasse oder einem Objekt) eineNachricht. Dieser prüft, ob er mit dieser Nachricht etwas anfangenkann, und reagiert gegebenenfalls entsprechend. Die Syntax zumSenden von Nachrichten hat folgende elementare Gestalt:

[Empfanger Nachricht]

Der Empfänger ist entweder eine im Kontext gültige Klasse oder eineim Kontext gültige Objektreferenz. Die   Nachricht   ist der Nameeiner Methode samt aller eventuellen Parameter, die auf dem Emp-fänger aufgerufen wird.

Konkret könnte das so aussehen:

[kaffeeMaschine kaffeeKochen][Auto neuesAuto]

Da der erste Buchstabe von  kaffeeMaschine ein Kleinbuchstabe ist,wäre Ersteres konventionsgemäß eine Nachricht an das Objekt, dasvon der zuvor deklarierten und initialisierten ObjektvariablenkaffeeMaschine  referenziert wird. Das Zweite hingegen wäre eineNachricht an die Klasse  Auto, da der erste Buchstabe von  Auto einGroßbuchstabe ist.

Nachrichten können parameterlos sein (wie die beiden Nachrichten

oben), und sie können Parameter erwarten. Nachrichtenparameterfolgen im Nachrichtennamen nach einem Doppelpunkt, wobei derDoppelpunkt Teil des Nachrichtennamens ist. Zum Beispiel sendet

[ich trinken: kaffee]

dem von   ich   referenzierten Objekt die Nachricht   trinken:   undübergibt dabei das von kaffee referenzierte Objekt.

Wenn eine Nachricht mehrere Parameter hat, folgen diese nachweiteren Namensteilen, die ebenfalls jeweils mit einem Doppel-punkt abgeschlossen werden:

[ich trinken: kaffee essen: kuchen];

oder:

[ich trinken: kaffee essen: kuchen mitPerson: mrPresident];

12 | Kapitel 2: Syntax

Page 21: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 21/224

Beachten Sie, dass zwischen den Parametern keine Kommata ste-hen. Mehr zu den Regeln für die Namen und die Nutzung vonNachrichten erfahren Sie im Kapitel 12, Messaging , bei der Beschrei-

bung der Definition eigener Nachrichten.Nachrichten sind Ausdrücke, die entweder zu einem Wert (einerObjektreferenz oder einem elementaren C-Wert, z. B.   int) aus-gewertet werden oder leer (void) sind. Nachrichten, die nicht  void

sind, können geschachtelt werden, zum Beispiel:

if ([kaffeeMaschine kannKaffeeKochen]) {[ich trinken: [kaffeeMaschine kaffeeKochen]];

}

Funktionell können Sie sich das Senden einer Nachricht als Äquiva-lent zum Aufruf einer Methode vorstellen. Eine Nachricht an eineKlasse entspricht dem Aufruf einer Klassenmethode, eine Nachrichtan ein Objekt dem Aufruf einer Instanzmethode.   [objekt machDas]

entspräche also einem objekt.machDas() in Java und ähnlich struktu-

rierten Programmiersprachen. Das vorangehende Codefragmentkönnte in einer solchen Programmiersprache also folgendermaßenaussehen:

if(kaffeeMaschine.kannKaffeeKochen()) {ich.trinken(kaffeeMaschine.kaffeeKochen());

}

Wie Sie eigene Nachrichten definieren, erfahren Sie in Kapitel 4 im

Abschnitt   »Methoden« auf Seite 38, wie der Benachrichtigungs-mechanismus intern funktioniert und wie Sie in ihn eingreifenkönnen, in Kapitel 12, Messaging .

CompilerdirektivenCompilerdirektiven sind Anweisungen an den Compiler, bestimm-ten Code zu generieren. Sie haben immer folgende Gestalt:

@name

Compilerdirektiven werden zu den unterschiedlichsten Zwecke ein-gesetzt: zur Deklaration und Definition von Klassen, zur Deklarationvon Protokollen, für die Ausnahmeverarbeitung, für die Speicher-verwaltung usw. Beispiele sind unter anderem die Direktiven

Compilerdirektiven | 13

Page 22: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 22/224

@implementation   und   @end, die eine Klassendefinition einrahmen,@class, die einen Klassennamen bekannt macht, oder   @private,@public usw., die die Sichtbarkeit von Instanzvariablen steuern.

Die  @autoreleasepool-Direktive aus dem einleitenden Beispiel be-zieht sich beispielsweise auf den nachfolgenden Block (den gesam-ten Code in den geschweiften Klammern) und dient der Speicher-verwaltung. Sie weist den Compiler an, Code zu generieren, derdafür sorgt, dass für den Block ein Auto-Release-Pool verfügbar ist.Dass ein solcher verfügbar ist, wird von den Cocoa-Bibliothekenvorausgesetzt, auf die der Code zurückgreift. Wäre kein Auto-

Release-Pool verfügbar, würde das zu Speicherlöchern führen.

Wir werden die verschiedenen Compilerdirektiven in den Abschnit-ten zu den entsprechenden Themen behandeln. Eine Aufstellungaller Compilerdirektiven finden Sie im Kapitel 18, Alternative Platt-

 formen.

LiteraldeklarationenObjective-C definiert ein paar neue Syntaxformen für Literale, mitdenen einige häufig genutzte Objekttypen leichter erstellt werdenkönnen. Wie Compilerdirektiven werden auch Literaldarstellungenmit dem  @-Zeichen eingeleitet. Von einfachen Compilerdirektivenunterscheiden sie sich dadurch, dass auf das @-Zeichen ein weiteres

Nicht-Buchstabenzeichen (also [, {, ") oder ein gewöhnliches Zahl-literal, folgt.

Objective-C definiert Literale für Strings (@"…"), Arrays (@[]), Dictio-naries (@{…}) und für Zahlobjekte (z. B.  @2.1415). Alle Literale erstel-len Objekte, die unveränderlich sind. Diese Arten von Literalenwerden wir uns in den folgenden Unterabschnitten kurz ansehen.

Array-, Dictionary- und Zahlliterale gibt es erstseit Mac OS X 10.8 bzw. iOS 6.0, und siewerden von den Entwicklungswerkzeugen erstseit Clang 4.0 unterstützt.

14 | Kapitel 2: Syntax

Page 23: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 23/224

Stringliterale

@"…"  definiert ein  Objective-C-Stringliteral. Objective-C-Stringlite-rale werden vom Compiler standardmäßig in Objective-C-Objektedes Typs   NSString  umgewandelt.   @"…"-Stringliterale sind also imGegensatz zu C-Strings (denen kein  @-Zeichen vorangestellt wird,z. B.  "Ein C-Stringliteral") Objekte und verhalten sich deswegenwie die Stringobjekte anderer objektorientierter Programmierspra-chen. Die Klasse NSString bringt bereits eine Menge von Methodenmit, mit denen Sie Objective-C-Strings verarbeiten können.

Die vom Compiler für Objective-C-Stringlite-rale zu verwendende Klasse kann mit demCompilerschalter   -fconstant-string-classeingestellt werden.

Array-Literale

@[…]  definiert ein   Array-Literal. Die Elemente des Arrays werdendurch Kommata getrennt zwischen den eckigen Klammern angege-ben:

@[@"eins", @"zwei", @"drei"]

Array-Literale werden vom Compiler in NSArray-Objekte übersetzt.

NSArray-Objekte können nur Objekte enthalten, aber diese Objektekönnen beliebigen Typs sein, d. h., ein Array kann Instanzenverschiedener Klassen enthalten. Folgendermaßen könnte man einArray deklarieren, das einen String und ein weiteres Array mit zweiZahlen enthält:

@[@"12-12-12", @[@48.857731, @2.339407]];

Das zweite Array enthält zwei Zahlen, die als Zahlobjekte angege-ben werden müssen, da   NSArray-Objekte nur Objekte enthaltenkönnen. Literale für Zahlobjekte werden weiter unten in diesemAbschnitt beschrieben. Literaldeklarationen können zur Verbes-serung der Lesbarkeit wie im folgenden (etwas extremen) Beispielüber mehrere Zeilen aufgeteilt werden:

Literaldeklarationen | 15

Page 24: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 24/224

NSArray *position = @[@"12-12-12",@[

@48.857731,

@2.339407]];

Dictionary-Literale

@{…} definiert ein   Dictionary-Literal. Dictionaries oder Wörterbü-cher verknüpfen einen Schlüssel, der ein beliebiger Objektwert seinkann, mit einem Wert, der ebenfalls ein beliebiger Objektwert seinkann. Zwischen Schlüssel und Wert steht jeweils ein Doppelpunkt(Schlussel:Wert). Mehrere Schlüssel/Wert-Paare werden als kom-maseparierte Liste angegeben:

@{@"datum" : @"12-12-12",@"koords" : @[@48.857731, @2.339407]

};

Dictionary-Literale werden vom Compiler in NSDictionary-Objekteübersetzt. Als Dictionary-Schlüssel können normalerweise beliebigeObjektwerte verwendet werden, vorausgesetzt, die Objekt unter-stützen das Protokoll   NSCopying   (das in  Kapitel 9,   Objektlebens-zyklus, im Abschnitt »Objekte kopieren« auf Seite 95 beschrieben

wird). Die Schlüssel müssen Strings sein, wenn das DictionaryKey/Value-Coding konform sein soll (siehe Kapitel 13,  Key/Value-Coding ).

Literale fu r Zahlobjekte

In Objective-C können die skalaren C-Zahltypen, z. B.   int  oder

float, genutzt werden. Außerdem definieren die Cocoa-Bibliothe-ken eigene skalare Zahltypen, z. B. NSInteger oder CGFloat, die einekonsistente Zahldarstellung auf unterschiedlichen Plattformen (32Bit vs. 64 Bit) gewährleisten. Daneben bieten die Cocoa-Biblio-theken den Objekttyp   NSNumber, der als Objekt-Wrapper für dieverschiedenen Zahltypen dient. Dieser wird z. B. benötigt, wenn

16 | Kapitel 2: Syntax

Page 25: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 25/224

Zahlen in einem  NSArray-Objekt gespeichert werden sollen, da dieCocoa-Collection-Typen nur Objekte aufnehmen können.

Zahlobjekte können durch eine der vielen   NSNumber-Klassennach-

richten oder mithilfe von  numerischen Objektliteralen  erstellt wer-den. Ein numerisches Objektliteral wird deklariert, indem einemgewöhnlichen Zahlliteral ein   @-Zeichen vorangestellt wird, zumBeispiel:

@3 // Entspricht dem int-Wert [email protected] // Entspricht dem double-Wert 3.1415@YES // Entspricht dem BOOL-Wert YES

@'a' // Entspricht dem char-Wert 'a'

Wenn der gewünschte repräsentierte skalare Wert vom Standardtypfür Zahlliterale des entsprechenden Typs abweicht, kann dieserdurch ein Postfix (U, L, F) angegeben werden, zum Beispiel:

@3L // long-Wert@3U // unsigned [email protected] // float-Wert

Seit Mac OS X 10.7 nutzt Objective-C fürNSNumber-Objekte sogenannte  Tagged Pointer .Das sind markierte Zeiger, die in den freienBits der Zeigeradresse direkt den Wert undeinen Typcode für das Objekt enthalten. DaObjective-C damit die teurere Objekterstellung

und -auflösung spart, können die   NSNumber-Zahlobjekte erheblich leichtgewichtiger undschneller als die Wrapper-Klassen anderer Pro-grammiersprachen sein.

Auf das @-Zeichen muss ein Zahlliteral folgen, d. h., Folgendes gehtnicht:

int zahl = 3;NSNumber *zahlobjekt = @zahl; // Geht nicht

Nutzen Sie stattdessen die im nächsten Abschnitt vorgestelltenWrapper-Ausdrücke.

Literaldeklarationen | 17

Page 26: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 26/224

Wrapper-Ausdru cke

Wrapper-Ausdrücke (Apple bezeichnet sie als »Boxed Expressi-ons«) ermöglichen Ihnen, die Werte von C-Ausdrücken in denkorrespondierenden Objective-C-Objekttyp umzuwandeln. Wrap-per-Ausdrücke nutzen die folgende Syntax:

@(…)

Einen Wrapper-Ausdruck könnten Sie folgendermaßen nutzen, umeinen skalaren Zahlwert in ein Zahlobjekt umzuwandeln:

int zahl = 3;NSNumber *zahlobjekt = @(zahl); // Geht

Wrapper-Ausdrücke unterstützen neben numerischen AusdrückenEnums, BOOL und C-Strings, zum Beispiel:

int zahl = 3;NSNumber *istUngerade = @((BOOL)zahl%2);char *cString = "Hallo";

NSString *objcString = @(cstring);

BlocksBlocks ist eine Syntax zur Definition von Funktionsausdrücken. Siewurden von Apple zur Übernahme in den C-Standard eingereichtund kommen unter Objective-C immer häufiger zum Einsatz. Sie

werden unter anderem unter GCD (Grand Central Dispatch), dervon Apple eingeführten Parallelisierungsinfrastruktur für Cocoa,genutzt, aber auch zur Definition einfacher Delegate-Funktionen,z.B. beim Vergleich oder bei der Enumeration von Objekten.

Blocks können inline definiert oder Blockvariablen zugewiesen werden.

Eine Blockvariable wird folgendermaßen deklariert:

Ruckgabetyp   (^Variablenname)(Parameterliste)

Eine Blockdefinition hat folgende Gestalt:

^(Parameterliste) {Anweisungen}

Folgendermaßen könnte man einen einfachen Block definieren, derzwei Strings verkettet:

18 | Kapitel 2: Syntax

Page 27: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 27/224

NSString * (^str_concat)(NSString *, NSString *) =^(NSString *head, NSString *tail) {

return [NSString stringWithFormat: @"%@%@", head, tail];}

Die Deklaration der Blockvariablen   str_concat   sagt, dass dieserBlock zwei   NSStrings erwartet und einen   NSString   liefert. DiesenBlock würden Sie folgendermaßen nutzen:

str_concat(@"Kopf und ", @"Schwanz");

Das diesen Abschnitt abschließende Beispiel enthält ein Blockliteral,das eine Funktion beschreibt, die bei der Enumeration eines Arrays

auf allen Elementen aufgerufen wird. Eine ausführlichere Beschrei-bung des Blocks-Konzepts finden Sie im Abschnitt »Blocks« auf Seite18.

Ein zweites Beispiel

Schauen wir uns nun ein nicht mehr ganz so primitives Beispiel an,in dem diese Syntaxstrukturen zur Anwendung kommen. Sie sollten jetzt in der Lage sein, diesem Code zu folgen:

#import <Foundation/Foundation.h>int main(int argc, const char *argv[]){

@autoreleasepool {id preise = @[@"ein Zeitungsabo",

@"eine Kaffeemaschine",@"einen Computer",@"eine Reise",@"ein Auto"

];  1NSUInteger anzahl = [preise count];2int zufall = arc4random_uniform((UInt32)anzahl);3id verlosung = [NSMutableString new];4

[verlosung appendString: @"Sie hatten"];5

[preise enumerateObjectsUsingBlock:  6^(id obj, NSUInteger idx, BOOL *stop) {

id format = idx == 0 ? @"%@" :idx < anzahl - 1 ? @", %@" :

@" oder %@";7[verlosung appendFormat: format, obj];8

}];9[verlosung appendString: @" gewinnen konnen."];:

Ein zweites Beispiel | 19

Page 28: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 28/224

Page 29: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 29/224

7   Ermittelt mithilfe des ternären Bedingungsoperators einen fürdie Position des aktuellen Array-Elements geeigneten For-matstring.

8   Sendet verlosung die Nachricht appendFormat: mit dem ermit-telten Format und dem aktuellen Objekt als Argument. Hängtden Wert des aktuellen Array-Elements mit dem Format for-matiert an den String an.

:   Schließt den String, nachdem die Elemente des Arrays in ihneingebaut wurden, mit einer weiteren   appendString:-Nach-

richt.;   Protokolliert den String mit der Bibliotheksfunktion NSLog()

auf der Konsole.

<   Prüft, ob die Zufallszahl einen Gewinn darstellt, und sorgtdafür, dass die entsprechende Ausgabeanweisung zur Ausfüh-rung kommt. (Sie fragen sich, was das  -2 soll? Haben Sie sich

noch nie gewundert, warum Sie den Hauptgewinn nicht be-kommen haben?)

=   Nutzt einen Objektindexer, um ein Element aus einem Array-Objekt abzurufen.

Die Ausgabe könnte folgendermaßen aussehen (wir haben den Textetwas formatiert, um ihn besser lesbar zu machen):

2012-12-08 17:13:29.233 Gewinnspiel[20151:303]Sie konnen ein Zeitungsabo, eine Kaffeemaschine,einen Computer, eine Reise oder ein Auto gewinnen.2012-12-08 17:13:29.236 Gewinnspiel[20151:303]Sie haben eine Kaffeemaschine gewonnen.

Wenn Sie  so ungefähr  erkennen konnten, wieder Code in diesem Beispiel funktioniert, soll-

ten Sie dazu in der Lage sein, dieses Buch zunutzen. Ist das jedoch nicht der Fall, sollten Siesich zunächst mit einem geeigneten Buch hin-reichende Kenntnisse einer anderen Program-miersprache aneignen (am besten C oder eineProgrammiersprache, deren Syntax an C ange-lehnt ist).

Ein zweites Beispiel | 21

Page 30: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 30/224

Page 31: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 31/224

KAPITEL 3

Objekte

Objekte sind der Angelpunkt der objektorientierten Programmie-rung. Sie sind der Stoff, aus dem Ihre Programme gewebt sind.

Für die, die noch nie mit einer objektorientierten Programmier-sprache gearbeitet haben: Alle Programme bestehen aus Daten undOperationen. Bei prozeduralen Programmiersprachen wie C sinddas jeweils eigenständige Programmkomponenten: Daten, die in

einem Speicher festgehalten und über Variablen im Programmreferenziert werden, und Funktionen, die auf diese Daten zugreifen.In objektorientierten Programmiersprachen werden Daten undOperationen zu Einheiten zusammengefasst, die als   Objekte   be-zeichnet werden.

Wie in den meisten anderen objektorientierten Programmierspra-

chen sind Objekte auch in Objective-C opake Strukturen, die dyna-misch in einem speziellen Speicherbereich, dem Heap, angelegt undverwaltet werden. Sie können nur über   Referenzen   festgehalten,manipuliert und zwischen Programmteilen ausgetauscht werden.

Objektvariablen und Zeiger

In Objective-C werden Objektreferenzen durch klassische C-Zeigerrepräsentiert und implementiert. Ein C-Zeiger ist eine Variable, diedie Adresse eines Speicherorts festhält. Zeigervariablen werdenfolgendermaßen deklariert:

Typ   *Variablenname;

| 23

Page 32: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 32/224

Der Zeigerindikator  *  zeigt an, dass eine Variable deklariert wird,die einen Zeiger auf einen Wert des angegebenen Typs enthält. Der*   wird entweder nach dem Typ oder vor dem Variablennamen

angegeben (in Objective-C ist die Stellung vor dem Variablennamenüblicher).

Es gibt zwei Operatoren zur Interaktion mit Zeigervariablen:  &  istder Adressoperator , * der Dereferenzierungsoperator . &Variable lie-fert die Speicheradresse einer Variablen, *Variable den Wert an derSpeicheradresse, die eine Zeigervariable festhält.

Einen Zeiger, der die Adresse eines  int-Werts festhält, würde manin C also folgendermaßen deklarieren:

int *zahlzeiger;

Den Wert einer anderen Variablen weisen Sie dem Zeiger mithilfedes Adressoperators zu:

int zahl = 42;

int *zahlzeiger = &zahl;Den Wert, auf den ein Zeiger zeigt, rufen Sie mithilfe des Derefe-renzierungsoperators ab:

int zahl = 42;int *zahlzeiger = &zahl;NSLog(@"Die Antwort ist %i", *zahlzeiger);

Schauen wir uns den Unterschied zwischen einem Zeiger auf einenWert eines bestimmten Typs (int *) und einem Wert eines be-stimmten Typs (int) anhand eines Beispiels an:

int a = 1;int b = a;int *zeiger = &a;a = 2;NSLog(@"b ist %i, zeiger zeigt auf %i",b , *zahl);

// Liefert "b ist 1, zeiger zeigt auf 2"

a und b sind gewöhnliche Werttypvariablen. Wird b der Wert von a

zugewiesen, wird einfach der Wert von a kopiert. Spätere Änderun-gen von  a wirken sich nicht auf den Wert von  b aus.  b behält alsoden Wert 1, den a hatte, als sein Wert b zugewiesen wurde.

24 | Kapitel 3: Objekte

Page 33: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 33/224

Page 34: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 34/224

Page 35: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 35/224

Objekte erstellenWill ein Programm mit einem Objekt arbeiten, muss das System im

Speicher Platz dafür schaffen und diesen ordentlich initialisieren. In Java, C# und vielen anderen Sprachen werden all diese Operatio-nen angefordert und im Hintergrund abgewickelt, wenn eine Kons-truktorfunktion mit dem   new-Operator aufgerufen wird. Objec-tive-C kennt keinen   new-Operator. Stattdessen werden dienotwendigen Arbeiten explizit angefordert, indem Nachrichteneingesetzt werden, die konventionsgemäß bestimmte Operationen

wie die Reservierung und Initialisierung des Speichers für ein Ob- jekt vornehmen.

Diese Nachrichten sind die Klassennachrichten   +alloc   und   +new

(diese Nachricht ist Ihnen in unserem zweiten Beispiel bereitsbegegnet) und die Objektnachricht  init (bzw. Objektnachrichten,deren Name mit init beginnt). alloc sorgt dafür, dass der Speicher-platz für ein Objekt bereitgestellt wird,   init   dafür, dass dieser

Speicherplatz korrekt initialisiert wird. Üblicherweise werden dieseMethoden folgendermaßen gemeinsam verwendet:

id ding = [[Ding alloc] init];

new ist einfach ein Alias für diese Operation, d. h., folgende Zeile istder vorangegangenen vollkommen äquivalent:

id ding = [Ding new];

Die Basisklasse der Cocoa-Plattform,   NSObject, stellt die Grund-implementierungen für diese Nachrichten bereit. Eine ausführlicheBeschreibung finden Sie in Kapitel 9, Objektlebenszyklus.

Wenn Objekte bei der Erstellung mit bestimmten Werten initiali-siert werden sollen, können Klassen Initialisierungsmethoden an-bieten, die Parameter erwarten. Diese haben konventionsgemäßeinen Namen, der mit init beginnt. Beispielsweise bietet die KlasseNSString eine initWithFormat:-Methode, mit deren Hilfe ein String-objekt auf Basis eines Formatstrings initialisiert werden kann. WieSie die Initialisierungsmethoden Ihrer eigenen Klassen gestalten,wird in Kapitel 9, Objektlebenszyklus, beschrieben.

Objekte erstellen | 27

Page 36: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 36/224

Page 37: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 37/224

Ein Beispiel:

Schiff *titanic = schiff_bauen(@"Titanic");

Der   Schiff *-Zeiger   titanic   zeigt jetzt auf ein   Schiff-Objekt –vorausgesetzt, die C-Funktion  schiff_bauen()   liefert einen Zeigerauf ein Objective-C-Objekt mit dem Typ  Schiff. Wir können überdiesen Zeiger nun alle Operationen anfordern, die für den TypSchiff  definiert sind – ganz wie man es erwartet, wenn man mitstreng typisierten Programmiersprachen wie C oder Java vertrautist.

NSString *name = titanic->name;[titanic auslaufen];titanic.schubProzent = 50;

Nutzen Sie hingegen eine id-Referenz, um ein Objekt festzuhalten,können Sie auf dieser Referenz nur noch Operationen vornehmen,die der Compiler nicht statisch prüfen muss:

id titanic = schiff_bauen(@"Titanic");

[titanic auslaufen];[titanic setSchubProzent: 50];

Bei einer  id-Referenz haben Sie keinen Zugriff auf das  name-Feld.Auf die   schubProzent-Eigenschaft können Sie zugreifen, müssendabei aber die Zugriffsmethoden nutzen, hier den Setter  -setSchub

Prozent:.

Objekte vergleichenObjekte werden über Zeiger festgehalten. Werden Zeiger über den==-Operator verglichen, werden einfach die Werte der Zeiger, d. h.die Speicheradressen, die sie speichern, verglichen. Zwei Objekt-zeiger werden gemäß ==-Operator also nur dann als gleich betrach-

tet, wenn sie auf dasselbe Objekt zeigen, zum Beispiel:id text = @"123";id gleicherText = [NSString stringWithFormat:@"%@", @"123"];id gleicheReferenz = text;BOOL test 1 = text == gleicherText; // NOBOOL test 2 = text == gleicheReferenz; // YES

Objekte vergleichen | 29

Page 38: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 38/224

Wenn die Objekte einer Klasse ein anderes Vergleichsverhaltenaufweisen sollen, muss die Klasse entsprechende Einrichtungenbereitstellen. Alle Objekte besitzen eine   isEqual:-Methode, die

standardmäßig das gleiche Verhalten aufweist wie der ==-Operator.Klassen können diese überschreiben, um ein anderes Vergleichs-verhalten zu definieren (siehe  Kapitel 11,  Laufzeitinformationen).Manche Klassen definieren darüber hinaus spezielle Vergleichs-methoden. Beispielsweise definiert die Klasse   NSString   eineisEqualToString:-Nachricht, die Stringvergleiche schneller durch-führt, wenn sichergestellt ist, dass beide Objekte Strings sind.

Objekt-EnumerationWenn ein Objekt ein Container, d. h. ein Behälter ist, der andereObjekte enthält, können seine Elemente mit der for (Typelement in

container)-Schleifenstruktur enumeriert werden. Die Schnittstellefür diese   schnelle Enumeration   wird im Framework-Protokoll

NSFastEnumeration  definiert.  container  kann nur ein Objekt sein,dessen Klasse dieses Protokoll implementiert.   NSFastEnumeration

wird z. B. von   NSArray,   NSDictionary   und   NSSet   sowie vonNSEnumerator implementiert.

Zum Beispiel könnten wir die [preise enumerateObjectsUsingBlock:

…]-Nachricht im abschließenden Beispiel in Kapitel 2,  Syntax, fol-gendermaßen durch eine schnelle Enumeration ersetzen:

NSUInteger idx = 0;for (id obj in preise) {

id format = idx == 0 ? @"%@" :idx < anzahl - 1 ? @", %@" :

@" oder %@";[verlosung appendFormat: format, obj];idx++;

}

ObjektindizierungDie von Objective-C seit Xcode 4.4 (LLVM 4.0) unterstützte  Ob-

 jektindizierung  gestattet die Referenzierung der Elemente eines Col-

30 | Kapitel 3: Objekte

Page 39: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 39/224

lection-Objekts oder eines Collection-ähnlichen Objekts über dieklassische Array-Indizierungssyntax:

Objekt[Index]

Die Objektindizierung wird von den Cocoa-Klassen NSArray, NSSet

und  NSDictionary  sowie ihren veränderlichen Unterklassen unter-stützt.

Objekt[Index] kann als Ausdruck eingesetzt werden, der zum Wertdes entsprechenden Elements ausgewertet wird, oder als Lvalue, umden Wert des entsprechenden Elements zu setzen (wenn Objekt eine

veränderliche Collection repräsentiert). Zum Beispiel werden imnachfolgenden Code die Elemente des veränderlichen Arraysquadrate auf das Quadrat des Werts des entsprechenden Elementsim Array zahlen gesetzt:

id zahlen = @[@0, @1,@2];id quadrate = [NSMutableArray new];for (int i = 0; i < [zahlen count]; i++) {

quadrate[i] = @([zahlen[i] integerValue]*[zahlen[i] integerValue]);}

Die Array-Werte müssen für die arithmetische Operation erst mitder Nachricht -integerValue in elementare Zahlwerte umgewandeltwerden (da die numerischen Operatoren für Objekttypen nichtunterstützt werden). Das Ergebnis hingegen muss vor der Zuwei-

sung in ein Objekt umgewandelt werden, wozu hier ein Wrapper-Ausdruck genutzt wird, da die »Collection-Typen« nur Objektwertespeichern. Aus gleichem Grund werden bei Indizierungsausdrückendie zusammengesetzten Zuweisungsoperatoren nicht unterstützt.

Index kann (wie oben) ein ganzzahliger Wert oder ein Objektwertsein. Ist der Index ein ganzzahliger Wert, wird eine Array-Indizie-rung genutzt, ist er ein Objektwert, eine Dicitionary-Indizierung.

Beachten Sie, dass sich die Unveränderlichkeit der unveränderlichenCollection-Klassen nicht nur auf die Länge bezieht. Dass sie unver-änderlich sind, heißt auch, dass sie keine Nachrichten zur Änderungihrer Elemente unterstützen. Folgende scheinbar unschuldige undvom Compiler anstandslos akzeptierte Alternative zu unserem obi-

Objektindizierung | 31

Page 40: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 40/224

gen Code wird zur Laufzeit fehlschlagen, weil die gesendete Nach-richt nicht unterstützt wird:

id zahlen = @[@0, @1,@2];

for (int i = 0; i < [zahlen count]; i++) {// Funktioniert nicht!!!zahlen[i] = @(

[zahlen[i] integerValue]*[zahlen[i] integerValue]);}

Der Compiler kann die Operation nur prüfen, wenn die Variablemit einem konkreten statischen Typ typisiert ist. Ändern Sie den

Typ von  zahlen

  in NSArray *

, meldet der Compiler einen Fehler,wenn der Indizierungsausdruck als Lvalue eingesetzt wird.

Wie bei Objective-C üblich, sind auch Indizierungsausdrücke nursyntaktischer Zucker, der vom Compiler zu den entsprechendenNachrichten aufgelöst wird. Bei der Array-Indizierung sind dasobjectAtIndexedSubscript:   und   setObject:atIndexedSubscript:,bei der Dictionary-Indizierung   objectForKeyedSubscript:   und

setObject:forKeyedSubscript:. Sie können die Objektindizierungalso auch auf Ihren eigenen Klassen unterstützen, indem Sie dieentsprechenden Methoden implementieren. Es gibt allerdings keinProtokoll, das die entsprechende Schnittstelle beschreibt.

32 | Kapitel 3: Objekte

Page 41: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 41/224

KAPITEL 4

Klassen

Objective-C nutzt das klassenbasierte Modell der objektorientiertenProgrammierung. Jedes Objekt ist eine Instanz einer Klasse; anony-me, allgemeine Objekte wie z. B. in JavaScript gibt es nicht.

In logischer Hinsicht sind Klassen Typdefinitionen, die die »Eigen-schaften« und das »Verhalten« der Objekte bestimmen, die Instan-zen dieser spezifischen Klasse sind. Strukturell stellen sie die Ein-

heiten dar, in die Sie Ihren Code gliedern. Sie arbeiten in IhremCode mit Objekten, aber wie sich die Objekte verhalten und wozusie genutzt werden, bestimmen Sie in den Klassen, die Sie schreiben.In Ihrem Code sind Klassen Objekte, mit denen Sie ebenso arbeitenkönnen wie mit den Objekten, die Instanzen von Klassen sind. Indiesem Abschnitt werden wir uns mit den ersten beiden Aspektenbefassen.

In Objective-C sind die Deklaration und die Definition einer Klassezwei separate Einheiten. Zunächst wird die Schnittstelle einer Klassedeklariert, d. h., es wird bekannt gemacht, was nach außen undinnen sichtbar ist und für den Code der Klasse bzw. für Code, derObjekte des durch die Klasse definierten Typs nutzt, sichtbar ist.

Klassendeklaration und -definitionObjective-C nutzt Compilerdirektiven, um die Syntaxstrukturen fürdie Deklaration und die Definition von Klassen zu markieren. EineKlassendeklaration wird von der Compilerdirektive   @interface

eingeleitet, die Klassendefinition von der Compilerdirektive

| 33

Page 42: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 42/224

@implementation. Dementsprechend bezeichnet man die Deklara-tion als die Schnittstelle und die Definition als die Implementierung .

Schnittstelle und Implementierung stehen üblicherweise jeweils in

eigenen Dateien. Das ist üblich, aber nicht notwendig.

Schnittstellendeklaration

Die Schnittstelle enthält die Deklaration der Klasse, bietet aberkeine Implementierung. Objective-C-Schnittstellen sind wieC-Headerdateien und haben nichts mit Javas Interfaces zu tun. Sie

machen die Struktur einer Klasse bekannt, damit ihre Instanzen vonanderem Code genutzt werden können, der ihre Implementierungnicht kennt.

Eine Klassendeklaration hat in Objective-C folgende Struktur:

#import "Oberklasse.h"

@interface Klasse : Oberklasse {// In diesem Abschnitt stehen die Felddeklarationen}

// Hier stehen die Eigenschafts- und Methodendeklarationen

@end

Eine Klassendeklaration muss die Deklaration der Oberklasse ein-

schließen. Das erfolgt wie hier mit der Präprozessordirektive #import.Die eigentliche Deklaration wird von den Objective-C-Compiler-direktiven   @interface   und   @end   eingerahmt. Sie beginnt mit derAngabe des Namens der neuen Klasse. Auf ihn folgen ein Doppel-punkt und der Name der Oberklasse. Die Oberklasse ist die Klasse,die die neu definierte Klasse erweitert. Doppelpunkt und Oberklas-

senname entfallen nur, wenn Sie eine neue Basisklasse deklarierenwollen. Der Abschnitt »Vererbung und Polymorphie« auf Seite 56geht ausführlicher auf diese Aspekte ein.

Die anschließenden geschweiften Klammern sind der Bereich, indem die Felder oder Instanzvariablen der Klasse deklariert werden.

34 | Kapitel 4: Klassen

Page 43: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 43/224

Methoden- und Eigenschaftsdeklarationen folgen nach der schlie-ßenden geschweiften Klammer.

Schnittstellendateien tragen den Namen der Klasse, die darin de-

finiert wird, und die Dateinamenserweiterung   *.h. Üblicherweisewerden Klassenschnittstellen in eigenständigen Dateien gespeichert

 – theoretisch kann eine Schnittstellendateien aber beliebig viele@interface-Abschnitte enthalten.

Klassenimplementierung

Die Implementierung bietet die Definitionen zu den Deklarationender Schnittstelle; in ihr wird der Code für die Methoden formuliert.Implementierungen stehen in Dateien, die üblicherweise die Datei-namenserweiterung   .m   tragen (.mm  oder   .M  bei Objective-C++).Eine Implementierungsdatei enthält üblicherweise nur die Imple-mentierung einer Klasse, kann theoretisch aber beliebig viele Klas-senimplementierungen enthalten. Auch für Klassen, die keine

Methoden enthalten, muss eine (leere) Implementierungsdatei an-gegeben werden. Wird keine Implementierungsdatei angegeben,erzeugt der Compiler keinen Unterstützungscode für die Klasse.Der Form nach sieht eine Klassenimplementierung folgendermaßenaus:

#import "Klasse"@implementation Klasse

// Hier steht die Implementierung@end

Eine Implementierung muss immer die eigene Schnittstelle impor-tieren. Der Definitionscode steht zwischen den Compilerdirektiven@implementation und  @end.

FelderFelder halten die Daten eines Objekts fest. Es sind an die jeweiligeKlasseninstanz gebundene Variablen. In Objective-C werden Felderhäufig als Instanzvariablen oder kurz Ivars bezeichnet.

Felder | 35

Page 44: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 44/224

Felder deklarieren

Felder werden in der Schnittstelle in einem in geschweiften Klam-mern stehenden Block deklariert.

@interface Kind : Elter {int alter;NSString* name;}@end

Felder können privat, geschützt, öffentlich oder paketgebundensein. Die Sichtbarkeit von Feldern wird bei der Felddeklarationmit den Compilerdirektiven,   @private,   @protected,   @public   und@package deklariert.

@private

Privat. Felder sind im Code der Klasse auf der Instanz selbst undauf anderen Instanzen sichtbar.

@protected

Geschützt. Felder sind im Code der Klasse selbst und im Codevon ihr abgeleiteter Klassen auf der Instanz selbst und auf anderen Instanzen sichtbar.

@public

Öffentlich. Felder sind überall sichtbar.

@packagePaketsichtbarkeit. Felder sind innerhalb des Programms oderder Bibliothek sichtbar, in dem bzw. der die Klasse implemen-tiert wird. Für paketinternen Code verhalten sich die entspre-chenden Felder wie öffentliche Felder, für paketexternen Codewie private Felder. Diese Sichtbarkeit entspricht der  internal-Sichtbarkeit in C# und der Standard- oder Package-Sichtbarkeit

in Java.Eine Direktive gilt jeweils für alle auf sie folgenden Felddeklaratio-nen, bis sie von der nächsten Direktive überschrieben wird. DieSichtbarkeit wird also in Blöcken und nicht eigens für jedes Felddeklariert, wie es z. B. in Java üblich ist. Deklarationen, denenkeine Sichtbarkeitsdirektive voransteht, erhalten die Sichtbarkeit@protected.

36 | Kapitel 4: Klassen

Page 45: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 45/224

@interface Agent : Beamter {Auftrag *auftrag; //Implizit @protected@privateOrt *position;

@protectedNSString *codeName;@publicNSString *name;Agent *gegner;}@end

Felder referenzierenFelder können mit dem ->-Operator referenziert werden, wenn dieReferenz statisch typisiert ist. Beispielsweise greift  agent->name auf das name-Feld eines (fiktiven) Agent-Objekts agent zu.

Auf die Felder der aktuellen Instanz kann im Code der Klasse ohneQualifikation durch das Objekt zugegriffen werden. Das bedeutet,

self->name und  name sind im Klassencode äquivalent.

Objekte erhalten alle Felder, die in den Schnittstellen der Klasseselbst und ihrer Oberklassen deklariert sind. Neben den in dereigenen Schnittstelle deklarierten Feldern können auch alle nichtals @private markierten Felder auf diese Weise referenziert werden.

Das heißt natürlich auch, dass es unmöglichist, über Referenzen, die nicht mit einem kon-kreten statischen Typen deklariert sind, auf Objektfelder zuzugreifen.

Statische Felder

Objective-C bietet keine spezielle Syntax für statische Felder oderKlassenvariablen. Sie werden üblicherweise emuliert, indem in derImplementierungsdatei eine Variable deklariert wird, die nur in derKompilationseinheit sichtbar ist.

#import "Klasse.h"int anzahlObjekte;

Felder | 37

Page 46: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 46/224

@implementation Klasse@end

Da eine solche Variable nach außen unsichtbar ist, müssen Sie den

Zugriff darauf über Methoden steuern.

MethodenMethoden sind Funktionen, die mit einem Objekt oder einer Klasseverknüpft sind. Objekt- oder Instanzmethoden werden genutzt, umOperationen auszuführen, die auf den Feldern der jeweiligen In-

stanz operieren. Sie können den von den Feldern bestimmtenZustand eines Objekts abfragen oder ändern.   Klassenmethodenoder statische Methoden operieren auf der Klasse selbst und habenkeinen Zugriff auf Felder eines spezifischen Objekts.

In Objective-C definieren Methoden die Nachrichten, die ein Objektversteht. »Eine Methode aufrufen« und »einem Objekt eine Nach-

richt senden« sind in Objective-C äquivalente Ausdrücke. DerEmpfänger für eine   Instanznachricht   (Instanzmethode) ist eineKlasseninstanz, der Empfänger einer   Klassennachricht   (Klassen-methode) das Klassenobjekt, das die Klasse repräsentiert.

Welche Nachrichten ein Objekt versteht und wie ein Objekt auf eine Nachricht reagiert, wird in Objective-C nicht vollständig durchdie Methoden bestimmt, die für eine Klasse deklariert und definiert

sind. Objective-C bietet Mechanismen, die es ermöglichen, dyna-misch zur Laufzeit festzulegen, wie ein Objekt auf eine Nachrichtreagiert. Diese werden im Kapitel 12, Messaging , beschrieben.

Anders als bei Feldern gibt es bei Methoden keine Möglichkeit, dieSichtbarkeit zu steuern. In der Schnittstelle deklarierte Methodensind grundsätzlich öffentlich. Trotzdem kann man Methoden defi-

nieren, die eine begrenzte Sichtbarkeit haben. Das beste und dazugeeignetste Mittel sind private Klassenerweiterungen (siehe Kapitel 5,Kategorien und Klassenerweiterungen, Abschnitt »Klassenerweiterun-gen« auf Seite 65).

38 | Kapitel 4: Klassen

Page 47: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 47/224

Methoden deklarieren

Methoden werden üblicherweise in der Schnittstelle deklariert. Beider Deklaration wird der Empfänger (die Klasse oder eine Instanz),der Rückgabetyp, der Methodenname und eine Folge eventuellerParameter angegeben. Die allgemeine Syntax hat folgende Form:

 Art   [(Ruckgabetyp)]   Namensteil[: (Paramtyp)   Paramname][Namensteil: (Paramtyp)   Paramname] …

 ArtMethoden können Instanz- oder Klassenmethoden sein. Ob der

Empfänger ein Objekt oder die Klasse ist, wird angegeben,indem der Deklaration bei einer Instanzmethode ein --Zeichenvorangestellt wird und bei einer Klassenmethode ein +-Zeichen.Einer der beiden Indikatoren muss angegeben werden.

RückgabetypGibt den Typ des Werts an, den eine Methode zurückliefert.

Dieser wird gemäß der in Sprachen der C-Familie üblichenSyntax für Typumwandlungen in einer Klammer angegeben.Der Typ kann void sein (die Methode liefert nichts zurück) oderein beliebiger von Objective-C unterstützter Datentyp bzw. einZeiger auf einen solchen. Wird kein Rückgabetyp angegeben,wird der Methode der Standardrückgabetyp id zugewiesen.

Namensteil

Der Name einer Methode kann aus einem oder mehrerenNamensteilen bestehen. Ein Namensteil muss vorhanden sein.Wenn eine Methode einen Parameter hat, wird dieser im Na-men durch einen Doppelpunkt eingeleitet. Weiteren Parame-tern gehen weitere mit weiteren Doppelpunkten abgeschlosseneNamensteile voran.

ParamtypGibt den erwarteten Typ des Parameters an und steht wie derRückgabetyp in Klammern.

ParamnameDer Name des Parameters.

Methoden | 39

Page 48: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 48/224

Konkret sieht das so aus:

Methoden ohne Parameter 

Die allereinfachste Methodendeklaration könnte folgende Gestalthaben:

-ding;

Diese Deklaration besteht nur aus einer Empfängerangabe undeinem Methodennamen. Sie deklariert eine Instanzmethode mitdem Namen   ding, die keine Parameter erwartet und einen Wertdes Typs id zurückliefert. Im Sinne der Transparenz sollten Sie auf die Angabe des Rückgabetyps nicht verzichten. Die äquivalentevollständige Deklaration sieht also so aus:

-(id) ding;

Methoden mit einem Parameter

Wenn eine Methode einen Parameter erwartet, folgt dieser nacheinem Doppelpunkt auf den Methodennamen:

-(void) machWasMit: (id) ding;

Diese Deklaration deklariert eine Instanzmethode mit dem NamenmachWasMit, die einen Parameter des Typs  id  erwartet und keinenWert zurückliefert. Der Doppelpunkt ist Teil des Methodennamens(hier lautet dieser also machWasMit:). Der Parametertyp wird wie der

Rückgabetyp in Klammern angegeben.

Methoden mit mehreren Parametern

Methodenname und Parameterliste sind in Objective-C keine sepa-raten Einheiten, sondern werden ineinander verwoben.

- (void) machWasMit: (id) ding und: (id) nochEinDing;

Der vollständige Methodenname lautet dann machWasMit:und:.

Es ist nur ein Namensteil notwendig, d. h., die Namensteile, abernicht die Doppelpunkte vor weiteren Parametern, können wegge-lassen werden. Eine Methode, die zwei Parameter erwartet, könntealso auch so deklariert werden:

40 | Kapitel 4: Klassen

Page 49: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 49/224

- (void) machWasMitDingUndDing: (id) ding1 : (id) ding2;

Der Methodenname wäre dann machWasMitDingUndDing::. Von die-ser Form wird abgeraten.

Da die Parameterliste Teil des Methodennamens ist, gibt es inObjective-C keine Methodenüberladung. Ein alternatives Konzeptsind die sogenannten  Methodenfamilien  wie z. B. die Familie derinit-Methoden. Eine Methodenfamilie umfasst Methoden mit ähn-lichem Funktionsbereich, deren Name durch das gleiche »Schlüssel-wort« eingeleitet werden.

Methodenimplementierung

 Jeder Nachrichtendeklaration in der Schnittstelle sollte eine Nach-richtendefinition in der Implementierung entsprechen. Wenn derCompiler in der Implementierung keine kompatible Definitionfinden kann, warnt er, dass die Implementierung unvollständig ist.

Eine Definition beginnt mit einer Methodensignatur, die der in derDeklaration entspricht. Auf diese folgt ein Paar geschweifter Klam-mern, in dem der eigentliche Methodeninhalt definiert wird, zumBeispiel:

@interface Zahl : NSObject {@public int zahl;

}

-(int) malInt: (int) faktor;@end@implemention Zahl-(int) malInt: (int) faktor {

return zahl * faktor;}@end

Der Compiler ist nicht immer dazu in der Lage, unvollständige oder

falsche Implementierungen zu erkennen und zu melden. Abwei-chende Rückgabe- oder Parametertypen meldet er nur, wenn einerder Typen ein Objective-C-Typ (int, float usw.) ist. Beispielsweisewürde folgende Implementierung zu zwei Warnungen führen, dieSie darauf aufmerksam machen, dass Rückgabetyp und Parameter-typ nicht der Deklaration entsprechen, weil für beides statt int long

als Typ angegeben wird:

Methoden | 41

Page 50: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 50/224

@implemention Zahl-(long) malInt: (long) faktor {

return zahl * faktor;}

@end

Wenn die Typen in Deklaration und Definition jeweils Objektzeigersind, meldet der Compiler keinerlei Abweichungen. Folgende De-klaration

+(Zahl *) zahlAusString: (NSString *) text;

würde für den Compiler auch durch eine Definition wie

+(NSNumber *) zahlAusString: (NSArray *) text {...

}

erfüllt. Da das zur Laufzeit im besten Fall zum unmittelbarenProgrammabbruch, im schlimmsten Fall zu unvorhersagbaren Er-gebnissen führt, sollten Sie derartige Fehler vermeiden.

self 

Der Methodeninhalt definiert die Operation, die eine Methode fürdie Klasse oder das Objekt stellt. Er kann auf alle Strukturenzugreifen, die im Code der Klasse bekannt sind (weil sie in derKompilationseinheit selbst definiert werden oder mit #import in die

Kompiliationseinheit importiert werden).Ein entscheidender Unterschied zu C und den Methoden in anderenobjektorientierten Programmiersprachen ist, dass Objective-C-Me-thodendefinitionen die Nachrichten definieren, die eine Klasse bzw.die Objekte einer Klasse verstehen, und keine einfachen, an einObjekt oder eine Klasse gebundenen Funktionen darstellen. WennSie dem aktuellen Objekt eine Nachricht senden, brauchen Sie dazu

also einen Empfänger.

self ist ein spezieller Empfänger, der in allen Methodendeklaratio-nen definiert ist. Was  self  repräsentiert und welche Operationenmit   self   möglich sind, ist allerdings von der Art der Methodeabhängig. In Code, der ARC-basiert ist (siehe Kapitel 10, Speicher-verwaltung ), gelten folgende Regeln:

42 | Kapitel 4: Klassen

Page 51: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 51/224

• In einer Klassenmethode (im Beispiel unten +zahlMitInt:) istself ein konstanter Wert des Typs Class, der die Klasse selbstrepräsentiert.

• In einer gewöhnlichen Instanzmethode (im Beispiel unten z. B.-alsInt) ist   self   ein konstanter Zeiger auf einen Wert desKlassentyps, mit dem interagiert, der aber nicht geändertwerden kann.

• In einer Instanzmethode der  init-Familie (im Beispiel unten-initMitInt:) ist self ein Zeiger auf einen Wert des Klassen-typs, der geändert werden kann.

Schauen wir uns zur Illustration die Implementierung der folgendenSchnittstelle an:

@interface Zahl : NSObject {int zahl;

}+(id) zahlMitInt: (int) wert;-(id) initMitInt: (int) wert;

-(void) malInt: (int) faktor;-(void) malZahl: (Zahl *) andereZahl;-(void) zumQuadrat;-(int) alsInt;@end

Da die Ivar zahl in allen Instanzmethoden zugreifbar ist, können wir-alsInt   einfach implementieren, indem wir den Wert von   zahl

zurückliefern:-(int) alsInt {

return zahl;}

Der Zugriff auf  -zahl kann wie oben  unqualifiziert oder mit  self-

qualifiziert erfolgen, da die Ivar auf dem aktuellen Objekt gelesenwerden soll:

-(int) alsInt {return self->zahl;

}

Beide Formen sind im Prinzip äquivalent. Die Qualifizierung mitself  verhindert, dass versehentlich auf eine lokale Variable zuge-

Methoden | 43

Page 52: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 52/224

griffen wird, die das Feld verdeckt. Der Compiler warnt, wenn einelokale Variable erstellt wird, die ein Feld verdeckt.

Ebenso können wir -malZahl: implementieren, indem wir den Wert

von zahl mit dem Wert des Arguments multiplizieren:-(void) malInt: (int) faktor {

self->zahl *= faktor;}

Aber wir könnten   -zumQuadrat  nicht wie z. B. in Java implemen-tieren, indem wir unqualifiziert eine malInt()-»Methode« aufrufen.

-malInt ist eine Nachricht und muss an einen explizit anzugeben-den Empfänger gesendet werden. Im Klassencode wird die aktuelleInstanz mit self angegeben:

-(void) zumQuadrat {[self malInt: self->zahl];

}

Da zumQuadrat eine gewöhnliche Instanzmethode ist, kann self nur

als Empfänger für Nachrichten bzw. als Objektzeiger zur Inter-aktion mit Ivars genutzt werden.

In Methoden der init-Familie (mehr Informationen dazu finden Siein  Kapitel 9,  Objektlebenszyklus, im Abschnitt  »Objektinitialisie-rung« auf Seite 89) sind darüber hinaus auch Zuweisungen an self

erlaubt:

-(id) initMitInt: (int) wert {self = [self init];self->zahl = wert;return self;

}

Anders als z. B.   this   in Java ist   self   auch in Klassenmethodendefiniert. In Klassenmethoden repräsentiert self allerdings nicht die

Instanz, sondern das Class-Objekt, das der Compiler auf Basis derKlassendefinition bereitstellt. Über das   Class-Objekt können SieInformationen zur Klasse erhalten und neue Klasseninstanzen er-stellen. Aber da es keine Instanz ist, können Sie auf ihm nicht auf Instanzvariablen oder -methoden zugreifen, sondern nur auf Klas-senmethoden bzw. auf Funktionen, Variablen usw., die in derKompilationseinheit deklariert sind.

44 | Kapitel 4: Klassen

Page 53: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 53/224

Diese self-Referenz können Sie in Klassenmethoden beispielsweisenutzen, um sicherzustellen, dass stets ein Objekt mit dem richtigenLaufzeittyp erstellt und geliefert wird:

+(id) zahlMitInt: (int)wert {return [[self alloc] initMitZahl: wert];

}

Wird diese Klassennachricht einer   UngeradeZahl-Unterklasse vonZahl gesendet, wird eine  UngeradeZahl-Instanz erstellt, da  self dasKlassenobjekt repräsentiert, das Empfänger der Nachricht ist. Wärehier fest der Typ der Klasse vorgegeben worden, in der die Methode

definiert wird (Zahl), würde ein Zahl-Objekt erstellt.

Methoden aufrufen

In Objective-C werden die Begriffe  Methode aufrufen   und   einemObjekt eine Nachricht senden  häufig synonym verwendet, obwohlder zweite Begriff eigentlich weiter ist. In »statischen« Programmier-

sprachen bewirkt der Aufruf einer Methode (oder Funktion), dassvorab festgelegter Code ausgeführt wird. Der Aufruf wird statisch,d. h. bei der Kompilierung aufgelöst. Objective-C hingegen ist eine»dynamische« Programmiersprache, in der Aufrufe zur Laufzeitaufgelöst werden. Objective-C-Objekte empfangen Nachrichtenund entscheiden zur Laufzeit, welcher Code aufgerufen wird. Daskann der Code einer vorab definierten Methode sein, könnte aber

auch Code sein, der erst zur Laufzeit bestimmt wird. Die definiertenMethoden stellen also nicht notwendigerweise alle Nachrichten dar,die ein Objekt kennt (siehe Kapitel 12, Messaging ).

Da Sie das nun wissen: In der Regel definieren Sie die Nachrichten,die ein Objekt versteht, indem Sie Methoden als Funktionen im-plementieren, die an ein Objekt gebunden sind. Und wenn Sie

einem Objekt eine Nachricht senden, führt das in der Regel dazu,dass eine Methode aufgerufen wird, die auf diese Weise implemen-tiert wurde. Aber weder das eine noch das andere muss der Fall sein.

Wie in   Kapitel 2,   Syntax, bereits erläutert, wird eine Methodeaufgerufen, indem einem Empfänger eine Nachricht gesendet wird:

[Empfanger Nachricht]

Methoden | 45

Page 54: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 54/224

Nachfolgend finden Sie zur Auffrischung noch ein paar Beispieledafür, wie Sie einige der Methoden aufrufen, die wir im Abschnitt»Methoden deklarieren« auf Seite 39 deklariert haben:

// Eine Nachricht ohne Parameter[ding ding];// Eine Nachricht mit einem erwarteten Parameter[zahl zahlMalInt: 3];// Eine Klassennachricht mit mehreren Parametern[Person initMitName: @"Hugo"

alter: 33augenfarbe: @"Grun"];

Die  [ding ding]-Zeile wird Ihnen vielleicht seltsam erscheinen. InObjektive-C gibt es unabhängige Namensbereiche für Instanzvaria-blen und Nachrichten. Eine Instanzvariable, die den gleichen Na-men wie eine Nachricht hat, führt deswegen nicht zu Konflikten.

Varargs-Methoden

Objective-C nutzt die gleiche Syntax und Infrastruktur für Metho-den mit Unterstützung für eine beliebige Anzahl an Argumenten wieC. Die Deklaration in der Schnittstellendatei hat folgende Gestalt.

-(void) verarbeiteDinge: (id) ding1, ...;

Der Indikator , ... zeigt an, dass hier ein Varargs-Parameter folgt.Einem Varargs-Parameter muss immer mindestens ein benannter

Parameter vorangehen, der in der Regel (aber nicht notwendiger-weise) wie oben das erste Element in der Liste der erwartetenArgumente repräsentiert.

Zur Implementierung von Varargs-Methoden werden in Objecti-ve-C der Typ va_list und die Makros va_start, va_args und va_end

genutzt, die alle in der   __stdargs.h__-Headerdatei der C-Standard-

bibliothek definiert sind.va_start initialisiert eine va_list-Struktur in Bezug auf den letztenbenannten Parameter in der Parameterliste. va_args ruft das nächsteArgument mit dem angegebenen Typ aus der Liste ab.   va_end

schließt die angegebene Argumentliste, wenn sie nicht mehr benö-tigt wird.

46 | Kapitel 4: Klassen

Page 55: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 55/224

Möchten Sie einen Varargs-Parameter nutzen, müssen Sie irgendwiein Erfahrung bringen können, wie lang die Liste ist bzw. wann sie zuEnde ist. In der Cocoa-Bibliothek werden häufig   nil-terminierte

Listen genutzt. Eine solche könnten Sie folgendermaßen implemen-tieren:

-(void) machWasMit: (id) ding1, ... {va_list args;va_start(args, ding1);// Was mit ding1 machenid ding;while ((ding = va_arg(args, id))) {

//Was mit den restlichen ubergebenen Argumenten machen}va_end(args);}

Der Header für die Varargs-Infrastruktur muss gewöhnlich nichteigens importiert werden, da er bereits von den wahrscheinlich zumEinsatz kommenden Cocoa-Headern importiert wird.

Eine Varargs-Methode wie diese rufen Sie auf, indem Sie Varargs-Argumente durch Kommata getrennt angeben und das Ende derArgumentliste mit nil anzeigen:

[machWasMit: ding1, ding2, ding3, nil];

Varargs-Parameterlisten müssen nicht notwendigerweise nil-termi-niert sein. Es gibt z. B. Framework-Methoden wie  stringWithFor-

mat, die kein nil am Ende der Argumentliste erwarten:

[NSString stringWithFormat: @"Zahl %i und Wort %@", 1, @"Eins"]

Bei dieser Form gibt es nichts, was das Ende der Argumentlisteanzeigt. Der Compiler ist aber in der Regel dazu in der Lage, Sie zuwarnen, wenn Anzahl und Typ der Parameter falsch sein könnten.

EigenschaftenEigenschaften bzw. Properties kapseln und schützen den Zugriff auf die Daten von Objekten. Implementiert werden sie in Objective-Cwie in anderen Programmiersprachen über ein privates Feld undzwei Zugriffsmethoden, eine zum Setzen und eine zum Abrufen des

Eigenschaften | 47

Page 56: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 56/224

Feldwerts. In Objective-C haben diese Zugriffsmethoden konventi-onsgemäß folgende Signaturen:

-( Typ  )  Name (Getter)

-(void) setName : ( Typ  )  Variable (Setter).

In Objective-C sollten Sie anders als bei vielenanderen Programmiersprachen üblich den Na-men des Getters nicht mit get beginnen. DiesesPräfix zeigt gemäß den Cocoa-KonventionenMethoden an, die Werte über Referenzen bear-beiten. Da die Namen von Feldern und Metho-den in Objective-C separat verwaltet werden,kann der Getter den gleichen Namen wie dasHintergrundfeld haben. Theoretisch könnteauch das set in Settern weggelassen werden, dader Doppelpunkt, der das Argument anzeigt,Teil des Namens ist – aber diese Verwendung

gehört nicht zu den gängigen Objective-C-Kon-ventionen.

Manuell würde man eine   anzahl-Eigenschaften also auf folgendeWeise deklarieren und implementieren:

@interface Dinge : NSObject {@private int _anzahl;

}-(void) setAnzahl: (int) anz;-(int) anzahl;@end

@implementation Dinge-(void) setAnzahl: (int) anz {

_anzahl = anz;}-(int) anzahl {

return _anzahl;}@end

48 | Kapitel 4: Klassen

Page 57: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 57/224

Eigenschaften deklarieren

Objective-C vereinfacht den Einsatz von Eigenschaften durch eineintegrierte Syntax für ihre Deklaration und Definition. Sie könnenmit der  @property-Direktive in der Schnittstelle deklariert werden.Diese wird folgendermaßen verwendet:

@property [( Attribut, …)]  Typ Eigenschaft;

 Attribut

Die Attribute der Eigenschaftsdeklaration bestimmen Aussehenund Verhalten der Eigenschaft. Eine vollständige Liste finden

Sie in   Kapitel 10,   Speicherverwaltung , im Abschnitt   »Eigen-schaftsattribute« auf Seite 106.

Typ

Gibt den Datentyp der Eigenschaft an.

Eigenschaft

Der Name der Eigenschaft.

In der einfachsten Verwendung hat die   @property-Direktive fol-gende Form:

@interface Dinge : NSObject {}@property int anzahl;@end

Diese @property-Deklaration ist der manuellen Deklaration im letz-ten Abschnitt mit Zugriffsmethoden mit den Standardsignaturenfür Getter und Setter äquivalent.

Alle Eigenschaften werden mit einer eigenen, mit einem Semikolonabgeschlossenen @property-Direktive deklariert.

In der Schnittstelle deklarierte Eigenschaften sind wie Methoden

grundsätzlich öffentlich sichtbar. Nur die Les- und Schreibbarkeitkann über Eigenschaftsattribute gesteuert werden. Private Eigenschaf-ten können wie private Methoden mithilfe von Klassenerweiterungen(siehe   Kapitel 5,   Kategorien und Klassenerweiterungen, Abschnitt»Klassenerweiterungen« auf Seite 65) erstellt werden.

Eigenschaften | 49

Page 58: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 58/224

Synthetisierung deklarierter Eigenschaften

Deklarierte Eigenschaften können explizit  synthetisiert oder manu-ell implementiert werden. Gibt es weder eine explizite Synthetisie-rung noch eine manuelle Implementierung, werden deklarierteEigenschaften seit Xcode 4.4 automatisch synthetisiert.

Automatische Synthetisierung

Automatische Synthetisierung heißt, dass der Compiler für eine@property-Deklaration in der Schnittstellendatei das Hintergrundfeld

und die erforderlichen Zugriffsmethoden in der Implementierungs-datei erzeugt. Für eine Eigenschaft, die mit der Direktive  @property

(Typ) eigenschaft deklariert wurde, erzeugt der Compiler:

• ein privates Hintergrundfeld mit dem Namen _eigenschaft

• einen Getter mit der Signatur - (Typ) eigenschaft

• einen Setter mit der Signatur  - (void) setEigenschaft: (Typ)

wert

Anders gesagt: Wenn Sie eine Eigenschaft nicht weiter konfigurie-ren müssen, reicht es aus, sie in der Schnittstelle mit  @property zudeklarieren. Die erforderlichen Einrichtungen zum Arbeiten mit derEigenschaft erhalten Sie dann automatisch.

Bei der oben deklarierten Eigenschaft   anzahl  hieße das, dass ein

int-Feld des Namens _anzahl und zwei Methoden mit den Signatu-ren   -(int) anzahl   (Getter) und   -(void) setAnzahl: (int) wert

definiert sind und genutzt werden können.

Explizite Synthetisierung

Zur expliziten Synthetisierung können Sie in der Implementierungs-

datei die  @synthesize-Direktive nutzen. Eine explizite Synthetisie-rung ist bei neueren Werkzeugversionen in der Regel überflüssig.@synthesize wird folgendermaßen verwendet:

@synthesize   eigenschaft[= feld], ...;

@synthesize   weist den Compiler an, Zugriffsmethoden mit denNamen  eigenschaft  und   setEigenschaft:  sowie ein Hintergrund-

50 | Kapitel 4: Klassen

Page 59: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 59/224

feld mit dem Namen  eigenschaft oder, wenn  = feld angegeben ist,mit dem Namen  feld  zu »synthetisieren«, falls in der Schnittstellekein entsprechendes Feld deklariert wurde.

In der einfachsten Form hat eine   @synthesize-Direktive folgendeForm:

@synthesize anzahl;

Bei dieser expliziten Synthetisierung werden wie bei der automati-schen Synthetisierung ein  anzahl-Getter und ein  setAnzahl:-Settergeneriert. Anders als bei einer automatischen Synthetisierung wird

dem Namen des Hintergrundfelds kein Unterstrich vorangestellt.Der Name ist  anzahl, nicht  _anzahl. Das ist etwas, das Sie bei derUmstellung von einer expliziten auf eine automatische Synthetisie-rung (oder umgekehrt) beachten müssen.

Bei der Form

@synthesize anzahl=_menge;

würde statt eines anzahl-Hintergrundfelds ein _menge-Hintergrund-feld synthetisiert, falls im Feldabschnitt der Schnittstelle kein ent-sprechendes Feld deklariert ist.

Beachten Sie, dass synthetisierte Hintergrund-felder mit deklarierten Ivars in Konflikt tretenkönnen.

Deklarierte Eigenschaften implementieren

Sie können Zugriffsmethoden auch manuell implementieren. Dasist z. B. sinnvoll, wenn Sie mehr Funktionalität benötigen, als dieStandard-Getter und -Setter bieten, zum Beispiel.:

@interface Dinge :NSObject {}@property (nonatomic) int anzahl;@end

@implementation Dinge-(void) setAnzahl: (int) wert {

if (wert > 0) _anzahl = wert;

Eigenschaften | 51

Page 60: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 60/224

}@end

Der Compiler erkennt automatisch, dass  -setAnzahl:  ein explizit

definierter Setter für die deklarierte Eigenschaft anzahl sein soll, undsynthetisiert nur noch den Getter und das Hintergrundfeld.

Wenn Sie synthetisierte und selbst definierte Zugriffsmethoden kom-binieren, müssen Sie die Eigenschaft mit dem Attribut   nonatomic

versehen. Eigenschaften sind standardmäßig atomar, und die syn-thetisierten Methoden werden entsprechend implementiert. Imple-mentieren Sie eine der Zugriffsmethoden manuell, beschwert sich der

Compiler, weil Sie atomare und nicht atomare Zugriffsmethodennicht kombinieren können. Alternativ können Sie beide Zugriffs-methoden manuell definieren.

@dynamic

Die Direktive  @dynamic  garantiert dem Compiler, dass die Imple-

mentierung einer deklarierten Eigenschaft zur Laufzeit zur Ver-fügung stehen wird. Sie bewirkt, dass er nichts in Bezug auf dieEigenschaft unternimmt. Er generiert keine Zugriffsmethoden undHintergrundfelder bzw. meldet keine Warnungen oder Fehler.

@dynamic wird wie @synthesize verwendet:

@dynamic   Eigenschaft;

Wenn Sie @dynamic nutzen, müssen Sie dafür sorgen, dass Objektezur Laufzeit auf die entsprechenden Nachrichten reagieren, z. B.indem Sie die Nachricht über den Weiterleitungsmechanismus voneinem anderen Objekt verarbeiten lassen (siehe Kapitel 12,  Messa-

 ging ).

Eigenschaftszugriff Eigenschaften sind ein Konstrukt, dessen öffentliche Schnittstellezwei Methoden sind. Diese können Sie jederzeit explizit nutzen:

Dinge *dinge = [Dinge new];[dinge setAnzahl: 5];int zahl = [dinge anzahl];

52 | Kapitel 4: Klassen

Page 61: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 61/224

Neben der Nachrichtensyntax unterstützt Objective-C 2.0 die ausanderen objektorientierten Programmiersprachen bekannte Punkt-notation für den Zugriff auf Eigenschaften. Das heißt, bei  statisch

typisierten   Referenzen kann stattdessen folgender Code genutztwerden:

Dinge *dinge = [Dinge new];dinge.anzahl = 5;int anzahl = dinge.anzahl;

Vom Compiler wird dieser Code zu den gleichen Aufrufen aufgelöstwie der vorangehende nachrichtenbasierte Code. Die Punktnota-

tion bietet den Vorteil, dass der Compiler statisch prüfen kann, obdas Objekt die entsprechende Nachricht unterstützt. Außerdemlassen sich viele Operationen kompakter formulieren, da Zuweisun-gen ihre C-Semantik bewahren, d. h. Ausdrücke sind, die zum Wertder Eigenschaft ausgewertet werden. Der Code ließe sich also nochweiter vereinfachen:

Dinge *dinge = [Dinge new];int anzahl = dinge.anzahl = 5;

Außerdem sind neben der einfachen Zuweisungsanweisung auchdie zusammengesetzten Zuweisungsanweisungen definiert. Das be-deutet,

[dinge setAnzahl: [dinge anzahl] + 5];

kann mithilfe der Punktnotation zudinge.anzahl += 5;

verkürzt werden.

Komplexe Anweisungsfolgen wie

[dinge setAnzahl: 5];[dinge setAnzahl: [dinge anzahl] * 5];

int anzahl = [dinge anzahl];

könnten zu Folgendem verkürzt werden:

int anzahl = dingeAnzahl *= dingeAnzahl = 5;

Eigenschaften | 53

Page 62: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 62/224

Beachten Sie, dass die Punktnotation nur beiObjektreferenzen genutzt werden kann, diestatisch mit dem Typ (oder einer Unterklasse

des Typs) deklariert sind, für den die Eigen-schaft definiert wurde. Andernfalls (d. h. beieiner Referenz des Typs id oder einer Referenzdes Typs einer Oberklasse des Typs, für dendie Eigenschaft definiert ist) schlägt die stati-sche Typprüfung des Compilers und damit dieKompilierung fehl, obwohl die dynamischeNachrichtenauflösung zur Laufzeit die ent-sprechenden Methoden finden würde.

Die Punktnotation kann nicht nur verwendet werden, wenn dieEigenschaft explizit mit der  @property-Direktive deklariert wurde,sondern auch, wenn die Eigenschaft vollständig manuell mitanzahl- und  setAnzahl:-Nachrichten implementiert wurde. Da der

Compiler die Punktnotation in die entsprechenden Nachrichten andas Objekt übersetzt, könnte sie theoretisch auch für Nicht-Eigen-schaftsnachrichten verwendet werden. Von dieser Verwendungwird jedoch abgeraten.

Eigenschaftsattribute

Die  @property-Direktive unterstützt eine Reihe von Attributen zurSteuerung des Zugriffs, der Setter-Operationsweise, der Namen derZugriffsmethoden und zur Threading-Unterstützung. Diese Attri-bute werden in Klammern hinter der  @property-Direktive angege-ben. Mehrere Attribute werden durch Kommata getrennt:

@property (Attribut1, Attribut2, ...) Typ Eigenschaft;

Geben Sie hinter   @property  keine Attribute an, werden die Stan-dardattribute genutzt. Eine attributlose Eigenschaftsdeklaration(@propertyTyp Eigenschaft) entspricht unter ARC der Deklaration@property (readwrite,strong)   Eigenschaft. Eigenschaften sindstandardmäßig atomar, d. h., Eigenschaftsoperationen werden alsEinheit abgewickelt (siehe @nonatomic weiter unten).

54 | Kapitel 4: Klassen

Page 63: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 63/224

Setter- und Getter-Namen definieren

Die folgenden Attribute können Sie verwenden, um die Namen derzu nutzenden Zugriffsmethoden manuell festzulegen.

setter= Name

Zeigt an, dass die Setter-Methode den Namen  Name hat. Wennin der Implementierungsdatei keine entsprechende Methodevorhanden ist, wird sie synthetisiert (es sei denn, die Direktive@dynamic wird verwendet).

getter= Name

Zeigt an, dass die Getter-Methode den Namen Name hat. Wennin der Implementierungsdatei keine entsprechende Methodevorhanden ist, wird sie synthetisiert (es sei denn, die Direktive@dynamic wird verwendet).

Die Attribute in den nachfolgenden Bereichen schließen sich gegen-seitig aus, d. h., es kann jeweils nur ein Attribut aus einem Bereich

angegeben werden.

Zugriffsteuerung

Die folgenden Attribute steuern den Zugriff auf eine Eigenschaft.

readwrite

Zeigt an, dass eine Eigenschaft lesbar und schreibbar ist. In der

Implementierungsdatei müssen entweder explizit eine Setter-und eine Getter-Methode definiert werden, oder Setter- undGetter-Methoden werden synthetisiert (der Standardwert).

readonly

Zeigt an, dass eine Eigenschaft schreibgeschützt ist. In derImplementierungsdatei muss nur eine Setter-Methode definiertsein, bzw. es wird nur eine Setter-Methode synthetisiert.

Setter-Operation

Alle nachfolgenden Attribute steuern die Zuweisung an die Eigen-schaft und die Speicherverwaltung. retain und  assign kommen beiReferenzzählung zum Einsatz, strong und  weak bei Automatic Refe-rence Counting. Die Speicherverwaltung und die Bedeutung der

Eigenschaften | 55

Page 64: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 64/224

Eigenschaftsattribute wird in Kapitel 10, Speicherverwaltung , genauererläutert.

assign

Einfache Zuweisung. Wird üblicherweise für skalare Werteoder (bei Referenzzählung) für Objekte genutzt, die nicht inder Klasse erstellt wurden (der Standard).

retain

Bei der Zuweisung wird dem neuen Wert die retain-Nachrichtgesendet, dem alten die release-Nachricht.

strongEine starke Referenz. Solange es eine starke Referenz gibt, wirddas Objekt nicht dealloziert. Entspricht   retain   und ist derStandard bei Automatic Reference Counting.

weak

Eine schwache Referenz. Wird unter ARC genutzt und ent-

spricht   assign, sorgt aber dafür, dass die Referenz auf   nilgesetzt wird, wenn das Objekt dealloziert wird.

copy

Für die Zuweisung wird eine Kopie des übergebenen Objektsverwendet. Die Kopie wird mit der copy-Methode erstellt, d. h.,dieses Attribut kann nur für Objekte eingesetzt werden, die dasNSCopying-Protokoll unterstützen. Dem alten Wert wird eine

release-Nachricht gesendet.

Atomarita t

nonatomic

Zeigt an, dass die Zugriffsmethoden nicht atomar sind. Stan-dardmäßig sind Zugriffsmethoden atomar, ein entsprechendes

Attribut gibt es jedoch nicht.

Vererbung und PolymorphieDie Klassen einer  Programmierschnittstelle stehen in einem hierar-chischen Verhältnis, das dem der Familien, Gattungen und Artennaturwissenschaftlicher Taxonomien vergleichbar ist. Wenn Sie

56 | Kapitel 4: Klassen

Page 65: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 65/224

sich eine solche Klassenhierarchie wie einen Stammbaum vorstellen,bei dem die Wurzel oben ist, finden Sie unten   engere  oder  spezi-

 fischere Klassen, die mit zunehmender Genauigkeit die spezifischen

Eigenschaften einer immer kleiner werdenden Gruppe von Objek-ten beschreiben. Oben finden Sie weitere oder allgemeinere Klassen,die eine nach oben hin immer größer werdende Menge von Objek-ten unter einer stets schrumpfenden Anzahl von Gemeinsamkeitenbeschreiben. An der Spitze dieser Hierarchie steht die  Basisklasse(siehe Kapitel 8, NSObject), die die grundlegenden Gemeinsamkei-ten aller Objekte beschreibt, die Exemplare der ihr untergeordneten

spezielleren Klassen sind. Alle anderen Klassen sind   erweiterndeoder abgeleitete Klassen, die jeweils den  Begriff  ihrer  Elternklassenum die für ihre Exemplare spezifischen Eigenschaften erweitern.

Mit Ausnahme der Basisklasse sind alle Klassen einer Klassenhie-rarchie abgeleitete Klassen. Ein Objekt, das eine Instanz einer abge-leiteten Klasse B ist, besitzt neben den speziellen Eigenschaften undVerhalten von Objekten der Klasse   B  alle   speziellen und geerbten

Eigenschaften und Verhalten von Objekten der Klasse A, wenn A dieElternklasse von B ist.

Schauen wir uns zur Illustration zwei Klassen A und  B an, die durchfolgende Schnittstellen beschrieben werden (wie im Abschnitt»Schnittstellendeklaration« auf Seite 34  beschrieben, wird die El-ternklasse in der Schnittstellendeklaration mit einem Doppelpunkt

nach dem Klassennamen angegeben):@interface A : NSObject@property int a;-(int) zumQuadrat;@end

@interface B : A@property int b;

-(int) aMalB;@end

Die Klasse  A   ist von  NSObject, der Basisklasse der Cocoa-Klassen-hierarchie, abgeleitet. In Objective-C muss die Basisklasse immerexplizit angegeben werden. Wird in einer Klassendeklaration keineElternklasse angegeben, wird eine neue Basisklasse deklariert. DieKlasse B ist von A abgeleitet.

Vererbung und Polymorphie | 57

Page 66: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 66/224

Vererbung

Vererbung bedeutet, dass eine abgeleitete Klasse alles erbt, was ihreElternklassen definieren. Die Deklarationen oben vorausgesetzt, heißtdas, dass B alle Eigenschaften und Verhalten von A und NSObject erbt,da  A die Basisklasse  NSObject erweitert und  B seinerseits  A  erweitert.Konkret bedeutet es, dass im Code von  B  alle nicht privaten Ivars,Methoden und Eigenschaften von A (und NSObject) sichtbar sind. In B

kann auf die geerbte Eigenschaft a also zugegriffen wie auf die eigeneEigenschaft b. Die Implementierung von B könnte z. B. so aussehen:

@implementation B-(int) aMalB {return self.b*self.a;

}@end

Für einen Nutzer von Objekten des Typs  B  gibt es keinen Unter-schied zwischen den eigenen und den geerbten Eigenschaften und

Methoden, zum Beispiel:B *bObjekt = [B new]; // new wurde uber A von NSObject geerbtif (!(bObjekt.a == bObjekt.b &&

[bObjekt zumQuadrat] == [bObjekt bMalA])) {NSLog(@"Große Katastrophe: 0^2 != 0*0");

}

Vererbung ermöglicht es, die Eigenschaften, die eine Gruppe von

Klassen gemeinsam haben, in einer gemeinsamen Elternklasse zu-sammenzufassen. Beachten Sie an diesem Punkt, dass Klassen inObjective-C grundsätzlich konkret sind. Es bietet keine Einrichtungzur Definition abstrakter Klassen.

In Objective-C können Klassen anders als z. B. in C++ nur eineElternklasse haben. Protokolle (siehe Kapitel 6,  Protokolle) bieteneine zusätzliche Möglichkeit Gemeinsamkeiten in der Schnittstelle

zu beschreiben.

Eigenschaften und Verhalten u berschreiben

Wenn eine abgeleitete Klasse einen Aspekt des Verhaltens einerElternklasse ändern will, kann sie die entsprechende Definition ineiner beliebigen Elternklasse durch eine eigene Definition   über-

58 | Kapitel 4: Klassen

Page 67: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 67/224

schreiben. Die Neudefinition in der abgeleiteten Klasse   verdecktdann nach außen hin die Definition in der Elternklasse.

Zum Beispiel könnte   B  folgendermaßen die  -zumQuadrat-Methode

von A neu definieren:@implementation B-(int) zumQuadrat {

return pow(self.b, 2);}…@end

Die ursprüngliche -zumQuadrat-Methode von A ist nun auf  B-Objek-ten nicht mehr verfügbar.

Im Unterschied zu Sprachen wie Java ist es in Objective-C auchmöglich und üblich, Klassenmethoden zu überschreiben:

super

In einer abgeleiteten Klasse kann auf Elternklassenelemente überden speziellen Empfänger   super   zugegriffen werden.   super   sorgtdafür, dass mit der Suche nach einer Nachrichtendefinition bei derElternklasse begonnen wird. Zum Beispiel könnte man folgender-maßen mit super in der Implementierung von B auf die zumQuadrat-Definition von A zugreifen:

-(int) aQuadrat {return   [super zumQuadrat];

}@end

Ansonsten verhält sich super fast genau so wie self (siehe »self« auf Seite 42). Der einzige Unterschied ist, dass auch in init-Methodenkeine Zuweisung an super erlaubt ist.

Beachten Sie, dass super und die superclass-Nachricht unterschiedliche Funktionen haben.super   sorgt dafür, dass die Methodenauflö-sung bei der Oberklasse ansetzt, verändert dieKlasse von   self   aber nicht.   superclass   hin-gegen liefert das Klassenobjekt, das die Ober-klasse repräsentiert.

Vererbung und Polymorphie | 59

Page 68: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 68/224

Polymorphie

Der Begriff   Polymorphie   verweist darauf, dass eine Referenz desTyps   T  Objekte aller abgeleiteten Klassen   X,   Y,   Z  usw. festhalten

kann und dass ein Objekt vom Typ  T über Referenzen aller Eltern-klassen A, B, C usw. festgehalten werden kann.

Wenn ein Objekt den Typ B hat, der von einem Typ A abgeleitet ist,kann es als Objekt des Typs B oder als Objekt des Typs A behandeltwerden. Wird es als Objekt des Typs  A behandelt, werden von ihmnur Dinge verlangt, die Objekte des Typs  A beherrschen. Da B alle

Eigenschaften und Verhalten von   A   erbt, ist garantiert, dass einObjekt des Typs  B allen Anforderungen genügt, die an ein Objektdes Typs A gestellt werden können:

A *bObjekt = [B new];bObjekt.a = 3;NSLog(@"%i", [bObjekt zumQuadrat]);

Nützlich wird das, wenn man Objekte unterschiedlichen, aber ver-

wandten Typs in Bezug auf bestimmte Operationen gemeinsambehandeln kann. Stellen Sie sich z. B. vor, Sie müssten eine  Tankwart-Klasse für eine Verkehrssimulation schreiben. Sie würde nur interes-sieren, dass die Objekte, mit denen Sie zu tun haben, die  -(void)

tankFuellen: (float) liter-Nachricht verstehen. Ob ein Fahrzeugein Ferrari, ein Reisebus, eine Harley oder selbst ein Ausflugsdampferist, ist für einen Tankwart vollkommen irrelevant. Die  betanken-Me-

thode von Tankwart könnte also folgende Gestalt haben:-(void) betanken: (Kfz *)kfz {

while (kfz.benzin < kfz.tankvolumen) {[kfz tankFuellen: 1];

}

Und so könnte sie verwendet werden:

Ferrari *roterBlitz = [Ferrari new];Bus *linie1 = [Bus new];[tankwart betanken: roterBlitz];[tankwart betanken: linie1];

In Objective-C ist diese  Vielförmigkeit  nichts Besonderes, für dasvon der Sprache spezielle Einrichtungen bereitgestellt werden. Ob-

 jektreferenzen sind einfach mit Typinformationen versehene Zeiger,die für alle Objekte gleich sein. Sie können deswegen von Haus aus

60 | Kapitel 4: Klassen

Page 69: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 69/224

Werte beliebigen Typs referenzieren. Ein Zeiger auf einen Objekttypkann beispielsweise in einen Zeiger auf jeden beliebigen anderenObjekttyp umgewandelt werden. Der Compiler hätte gegen Folgen-

des in Objective-C kein Einwände:[tankwart betanken: (Kfz *)@"Auto"];

Die Typumwandlung selbst würde auch zur Laufzeit noch gelingen,und ein Fehler würde erst auftauchen, wenn in  -betanken auf demNSString-Objekt Operationen aufgerufen werden, die von NSString-Objekten nicht unterstützt werden (siehe Abschnitt »Typumwand-lungen« unten).

Objective-C unterstützt deswegen auch das sogenannte  Duck Ty- ping , das man üblicherweise eher mit Skriptsprachen ohne statischeTypprüfung verbindet.

Typumwandlungen

Vererbungsbeziehungen spielen bei der Umwandlung von Zeigernauf Objekttypen nur insofern eine Rolle, als dass implizite  Upcasts(Umwandlungen in einen Elterntyp) erkannt und akzeptiert werden.Ansonsten führen implizite Typumwandlungen immer zu einer Com-pilerwarnung, während alle expliziten Typumwandlung unkommen-tiert akzeptiert werden. Beispielsweise führt folgende Zuweisung beider Kompilierung nur zu einer Warnung, obwohl die Klassen NSArray

und NSString nicht in einem Vererbungsverhältnis stehen:

NSArray *text = @"Riskant";

Mit einem expliziten Cast können wir sogar diese Warnung unter-drücken:

NSArray *text = (NSArray *)@"Riskant";

Bei einer Sprache wie Java würde die implizite wie die expliziteTypumwandlung zu einem Kompilierungsfehler führen.

Zur Laufzeit gelingen Typumwandlungen, explizite wie implizite,immer (so etwas wie eine ClassCastException kennt Objective-Cnicht). Dass Zeiger- und Objekttyp inkompatibel sind, fällt erst auf,wenn zur Laufzeit auf dem Zeiger eine Operation angefordert wird,die das Objekt nicht unterstützt.

Typumwandlungen | 61

Page 70: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 70/224

Page 71: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 71/224

KAPITEL 5

Kategorien und

Klassenerweiterungen

Kategorien bieten eine Möglichkeit, bestehenden Klassen, aucheingebauten Framework-Klassen oder anderen Klassen, über derenQuellcode Sie nicht verfügen, nachträglich Methoden hinzuzufü-gen. Sie ermöglichen Ihnen also, die Funktionalität einer Klasse

nachträglich zu erweitern – eine Technik, die unter dem NamenMonkey Patching   bekannt ist. Alle Methoden, die Sie in einerKategorie auf einer Klasse definieren, werden zu einem Teil derursprünglichen Klasse.

Die Deklaration einer Kategorie wird angezeigt, indem bei derSchnittstellendeklaration hinter dem Klassennamen in Klammernder Name der Kategorie angegeben wird:

#import "Klasse.h"@interface Klasse (Kategorie)// Methodendeklarationen@end

Kategorien können nur Methodendeklarationen enthalten, keineFelder – es gibt also keinen Abschnitt mit Felddeklarationen. Das

heißt auch, dass Sie in Kategoriedeklarationen zwar mit  @propertyneue Eigenschaften deklarieren, diese in der Implementierungsdateiaber nicht mit   @synthesize   synthetisieren können – Getter undSetter müssen manuell definiert werden und können nur die Ein-richtungen, d. h. Felder nutzen, die von der ursprünglichen Klas-sendeklaration bereitgestellt werden. Tun Sie das nicht, meldet derCompiler nur eine Warnung, keinen Fehler. Kategorienamen haben

| 63

Page 72: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 72/224

einen eigenen Namensraum. Sie könnten beispielsweise also eineKategorie mit dem gleichen Namen wie die Klasse definieren.

Wenn Sie die Kategorie im gleichen Header wie die Klasse selbst

deklarieren, sind die darin deklarierten Methoden vollwertige Klas-senmethoden und können genau so eingesetzt und aufgebaut wer-den wie die Methoden der Klasse selbst. Kategoriemethoden habenZugriff auf alle deklarierten Einrichtungen der Klasse und könnenbeispielsweise sogar private Felder lesen.

Deklarieren Sie die Kategorie in einem eigenen Header, müssen Sie

in diesen den Header für die Klassendeklaration einschließen. Au-ßerdem müssen Sie in Code, der die Kategorie nutzt, zusätzlich zumKlassenheader den Kategorieheader einbinden. Tun Sie das nicht,meldet der Compiler einen Fehler, wenn Sie ARC (siehe Kapitel 10,Speicherverwaltung ) nutzen, oder eine Warnung, wenn Sie ARCnicht nutzen. Ansonsten unterscheiden sich die entsprechendenMethoden in keiner Weise von Kategoriemethoden, die in der

Klassendatei selbst deklariert werden.Dateien für Kategorien erhalten konventionsgemäß einen Namender Form klasse+kategorie.h und klasse+kategorie.m.

Wenn Sie in einer Kategorie eine Methode deklarieren, die dengleichen Namen wie eine Methode in der erweiterten Klasse hat,überschreibt die neue Deklaration die ursprüngliche Version. Der

super-Aufruf hat bei Kategoriemethoden die gleiche Semantik wiebei gewöhnlichen Klassenmethoden und ruft eine eventuelle Ober-klassenversion der Methode auf und nicht die Methode aus dererweiterten Klasse. Es gibt keine Möglichkeit, eine überschriebeneMethode der erweiterten Klasse aufzurufen. Es ist nicht festgelegt,was passiert, wenn mehrere Kategorien, die die gleiche Klasseerweitern, eine Methode mit dem gleichen Namen definieren. Ver-

meiden Sie diese Situation.Eine Kategorieimplementierung wird angezeigt, indem in der Klas-senimplementierung der Name der Kategorie in Klammern hinterdem Klassennamen angegeben wird:

64 | Kapitel 5: Kategorien und Klassenerweiterungen

Page 73: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 73/224

#import "Klasse+Kategorie.h"@implementation Klasse (Kategorie)//Methodendefinitionen@end

Die Methoden einer Kategorie müssen nicht implementiert werden.Wenn ein Implementierungsabschnitt für eine Kategorie vorhandenist, in dem die in der Kategorie deklarierten Methoden nicht voll-ständig definiert werden, meldet der Compiler eine Warnung. Gibtes keinen Implementierungsabschnitt, gibt es überhaupt keine Mel-dung. Eine deklarierte, aber nicht definierte Kategorie bezeichnetman als »informelles Protokoll« (siehe Kapitel 6, Protokolle).

KlassenerweiterungenKlassenerweiterungen sind anonyme Kategorien. Sie werden dekla-riert, indem der Name zwischen den Klammern nach dem Klassen-namen weggelassen wird:

interface Klasse ()

Der Unterschied zu einer gewöhnlichen Kategorie ist, dass die ineiner Klassenerweiterung deklarierten Methoden im eigentlichenImplementierungsabschnitt für   Klasse   definiert werden müssen.Klassenerweiterungen können Sie also nur für Klassen schreiben,bei denen Sie Zugriff auf den Quellcode haben.

Ab Clang/LLVM 2.0 können Klassenerweiterungen im Gegensatzzu Kategorien auch Feld- und Eigenschaftsdeklarationen enthalten.

Klassenerweiterungen werden vorwiegend eingesetzt, um die pri-vate Schnittstelle einer Klasse zu deklarieren. Dazu wird die Klassen-erweiterung in der Implementierungsdatei, nicht der Schnittstellen-datei deklariert:

#import "ding.h"@interface Ding ()@end@implementation Ding@end

Klassenerweiterungen | 65

Page 74: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 74/224

Page 75: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 75/224

KAPITEL 6

Protokolle

Protokolle sind Zusammenstellungen von Methodendeklarationen,die nicht mit einer bestimmten Klasse verknüpft sind. Sie sind dasObjective-C-Äquivalent zu Javas Interfaces und erfüllen die gleicheFunktion. (Genauer gesagt, entsprechen Javas Interfaces den Pro-tokollen von Objective-C, da Javas Interfaces von Objective-C-Pro-tokollen inspiriert wurden.)

Ein Protokoll wird nicht instantiiert. Klassen deklarieren ihre Kon-formität zu einem Protokoll und garantieren damit, dass ihre In-stanzen auf die entsprechenden Nachrichten reagieren. Der Zweckvon Protokollen ist es, Klassen, die nicht in einem Vererbungsver-hältnis stehen, eine Übereinstimmung in Bezug auf eine spezifischeMethodenschnittstelle deklarieren zu lassen. Konzeptionell sindProtokolle als weniger problematische Alternative zur Mehrfachver-

erbung gedacht. Nutzen Sie Protokolle, wenn man Klassen aus denunterschiedlichsten Klassenhierarchien zu bestimmten Zweckengleich behandeln können soll.

Ein Protokoll deklarierenProtokolle werden mit der @protocol-Direktive deklariert:

@protocol Protokoll// Methodendeklarationen@end

Die Methodendeklarationen in einem Protokoll haben genau diegleiche Form wie bei einer Klassendeklaration, zum Beispiel:

| 67

Page 76: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 76/224

@protocol Exportierbar-(id) exportieren;-(id) exportierenAls: (int) exportformat;-(NSArray *) exportformateAlsListe;

@end

Standardmäßig sind alle Methoden erforderlich, die ein Protokolldeklarieren. Eine Klasse, die ein Protokoll adoptiert, muss alle Metho-den implementieren, die von diesem Protokoll deklariert werden.

Optionale Protokollmethoden, die implementiert werden können,aber nicht implementiert werden müssen, können mit der @optional-

Direktive deklariert werden. Folgende Deklaration würde beispiels-weise die beiden letzten Methoden des Protokolls optional machen:

@protocol Exportierbar-(id) exportieren;@optional-(id) exportierenAls: (int) exportformat;-(NSArray *) exportformateAlsListe;@end

Die  @optional-Direktive bleibt in Geltung, bis sie durch eine neueDirektive aufgehoben wird. In einem  @protocol-Abschnitt könnenweitere erforderliche Methoden deklariert werden, indem die@required-Direktive vorgeschaltet wird, zum Beispiel:

@protocol Exportierbar@optional

-(id) exportierenAls: (int) exportformat;-(NSArray *) exportformateAlsListe;@required-(id) exportieren;@end

Es ist empfehlenswert, die   @required- und   @optional-Direktiveneinzusetzen, um erforderliche und optionale Methoden eindeutigzu kennzeichnen.

Protokollhierarchien

Ein Protokoll kann die Übereinstimmung mit anderen Protokollendeklarieren:

@protocol Protokoll <Protokoll_x, Protokoll_y, …>

68 | Kapitel 6: Protokolle

Page 77: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 77/224

Die Methoden des adoptierten Protokolls müssen nicht neu dekla-riert werden. Eine Klasse, die das übergeordnete Protokoll adop-tiert, muss alle nicht optionalen Methoden aller Protokolle in der

Liste implementieren.Es ist üblich, alle eigenen Protokolle das  NSObject-Protokoll über-nehmen zu lassen:

@protocol Protokoll <NSObject>

Das NSObject-Protokoll definiert die grundlegende Schnittstelle derNSObject-Klasse. Wenn Sie Ihre Protokolle die Konformität zum

NSObject-Protokoll deklarieren lassen, sorgen Sie dafür, dass Sieauf Referenzen, die auf den Protokolltyp eingeschränkt werden(siehe unten), die   NSObject-Methoden aufrufen können, die vonden referenzierten Objekten als Instanzen von Klassen aus derNSObject-Hierarchie notwendigerweise unterstützt werden.

Wie Sie aus der Existenz dieses NSObject-Protokolls schließen kön-nen, gibt es einen eigenen Namensbereich für Protokolle. Sie kön-nen für Protokolle also die gleichen Namen nutzen wie für Klassenoder Kategorien. Üblicherweise haben Protokolle wie Java-Inter-faces aber Namen, die auf »-ing« enden.

Vorwa rtsdeklaration

Wenn Ihre Protokolldeklarationen ein anderes Protokoll als Typ fürdie Parameter oder Rückgabewerte von Methoden nutzen, könnenSie die  @protocol-Direktive ähnlich der  @class-Direktive auch ein-setzen, um ein Protokoll vorab zu deklarieren:

@protocol Protokoll;

Protokolle implementierenDie Übereinstimmung bzw. Übernahme eines Protokolls wird inObjective-C mit spitzen Klammern angezeigt. Bei einer Klassende-klaration geben Sie die Namen der übernommenen Protokolle inspitzen Klammern hinter einem wahrscheinlichen Oberklassen-namen an:

@interface Klasse: Oberklasse <Protokoll> …

Protokolle implementieren | 69

Page 78: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 78/224

Sie können Protokolle auch in Kategorien implementieren:

@interface Klasse (Kategorie) <Protokoll>

Zwischen den spitzen Klammern steht der Name eines Protokollsoder eine kommaseparierte Liste von Protokollnamen. Wenn dasProtokoll in einer anderen Datei deklariert wird, müssen Sie gege-benenfalls den entsprechenden Header importieren, zum Beispiel:

#import "exportierbar.h"@interface Dokument : NSObject <Exportierbar> …

Eine Klasse, die die Übereinstimmung mit einem Protokoll dekla-

riert, garantiert, dass sie alle nicht optionalen Methoden des Pro-tokolls implementiert. Die Deklaration bewirkt, dass die im Pro-tokoll deklarierten Methoden auch für die Klasse deklariert sind.Die Protokollmethoden müssen in der Klasse also nicht noch einmaldeklariert, sondern nur noch in der Implementierungsdatei definiertwerden.

Definiert die Klasse bzw. Kategorie nicht alle nicht optionalenMethoden, die in den Protokollen deklariert werden, meldet derCompiler eine Warnung. Beachten Sie, dass diese Warnung entfällt,wenn das Protokoll auf einer Kategorie deklariert wird, für die eskeinen Implementierungsabschnitt gibt.

Optionale Methoden aufrufenWenn Sie eine als @optional deklarierte Protokollmethode aufrufenwollen, sollten Sie zuvor unbedingt prüfen, ob diese von der ent-sprechenden Klasse implementiert wird. Dazu können Sie die-respondsToSelector:-Nachricht des   NSObject-Protokolls nutzen,zum Beispiel:

if([dokument respondsToSelector: @selector(exportierenAls:)]) {

[dokument exportierenAls: (int) Exportformate.RTF];}

Beachten Sie, dass Sie die  respondsToSelector:-Nachricht an Emp-fänger, die mit dem Protokolltyp deklariert sind, nur dann sendenkönnen, wenn das Protokoll selbst die Konformität zum  NSObject-Protokoll deklariert, da die Nachricht für den Empfänger andern-falls nicht deklariert ist.

70 | Kapitel 6: Protokolle

Page 79: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 79/224

Protokolle als ReferenztypenBei der Deklaration von Feldern, Eigenschaften und Variablen

sowie den Rückgabe- und Parametertypen von Methoden könnenSie angeben, dass die referenzierten Objekte einem oder mehrerenProtokollen entsprechen:

id <Protokoll> @property Eigenschaft;

oder:

Klassenname <Protokoll> *Variable;

Beachten Sie, dass Sie das Protokoll nicht einfach anstelle eines Typsangeben können wie z. B. in Java (Protokoll *Variable versteht derCompiler also nicht). Ein Protokoll ist kein Typ und kann deswegenauch nur als zusätzliche Information zu einem Variablentyp ver-wendet werden.

Wie eine Klassenangabe ermöglicht die Protokollangabe dem Com-

piler, statisch zu prüfen, ob Operationen, die auf dem referenziertenObjekt vorgenommen werden, dem deklarierten Typ der Variablenentsprechen. Das heißt, der Compiler meldet einen Fehler, wennauf dieser Referenz eine Operation vorgenommen wird, die dementsprechenden Protokoll nicht konform ist. Diese Technik bietetIhnen sozusagen eine protokollbasierte Polymorphie. Sie ermöglichtIhnen, heterogene Objekte unter dem Aspekt ihrer Konformität zu

einem Protokoll einheitlich zu behandeln, ohne auf die Vorteileeiner statischen Typisierung verzichten zu müssen.

Informelle ProtokolleEinige der Eigenschaften von Protokollen können Sie emulieren,indem Sie eine Kategorie deklarieren, aber nicht implementieren.

Eine solche Kategorie bezeichnet man als informelles Protokoll, weilman nicht anzeigen kann, ob es implementiert wird oder nicht.Informelle Protokolle können also nicht genutzt werden, um denTyp einer Variablen genauer anzugeben, und bieten deswegen keineMöglichkeit für eine protokollbasierte Polymorphie.

Informelle Protokolle | 71

Page 80: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 80/224

Page 81: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 81/224

KAPITEL 7

Fehler und Ausnahmen

Objective-C und Cocoa unterscheiden Fehler und Ausnahmen.Fehler sind Probleme, die auf äußere Umstände zurückgehen, bei-spielsweise wenn eine Datei nicht lesbar, ein Netzwerk nicht er-reichbar ist oder ein Dokument das falsche Format hat. Ausnahmenhingegen sind Probleme, die auf innere Umstände, d. h. programm-interne Bedingungen, zurückgehen, z. B. dass eine Methode einen

Argumentwert erhält, mit dem sie nichts anfangen kann, oder dassein Array-Index die Array-Grenzen verletzt. Es gibt eigene Klassen,NSError   und   NSException, zur Beschreibung und Kapselung vonFehlern bzw. Ausnahmen, und es werden unterschiedliche Pro-grammstrukturen und -konventionen zu ihrer Bearbeitung einge-setzt.

Diese Unterscheidung von Fehler und Ausnahme und die Verwen-

dung dieser Begriffe unterscheidet sich erheblich von den Konven-tionen in vielen anderen Programmiersprachen. In Objective-C sindAusnahmen die Ausnahme und Fehler die Regel! Wenn ein Problemauftaucht, das sich im Kontext Ihres Programms beheben lässt,sollten Sie Fehler nutzen. Ausnahmen sollten Sie nur verwenden,wenn ein Problem auftaucht, das zum Abbruch des Programmsführen  sollte. Wenn Sie eine Parallele zu Java suchen: Fehler ent-

sprechen in der Regel einer   checked Exception, Ausnahmen hin-gegen einem Error oder einer RuntimeException.

| 73

Page 82: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 82/224

FehlerBei manchen Operationen muss man immer mit dem Auftreten von

Fehlern rechnen und kann die Information zu Fehlern und eventu-elle Wiederherstellungsoptionen gleich in das Programm einbauen.In Objective-C und Cocoa-Programmen nutzen Sie dazu  NSError-Objekte, die neben einem Fehlercode Informationstexte und sogarButton-Beschriftungen und damit verbundene Wiederherstellungs-aktionen für einen Dialog kapseln können, in dem der Fehler demBenutzer präsentiert werden kann.   NSError-Objekte werden von

Methoden, die derartige Operationen unternehmen, häufig nichtüber den Rückgabewert geliefert, sondern über einen Referenz-parameter. Die Methode erwartet ein  NSError **-Argument – d. h.statt einer Kopie eines Zeigers einen Zeiger auf einen Zeiger.

Betrachten wir beispielsweise die   stringWithContentsOfURL:-Me-thode der Klasse  NSString, mit der Sie den Inhalt einer über eineURL identifizierten Ressource in einen String laden können. Diese

hat folgende Signatur:

+ (id)stringWithContentsOfURL:(NSURL *)urlencoding:(NSStringEncoding)enc

error:(NSError **)error

Eine solche Methode nutzen Sie üblicherweise folgendermaßen

NSError * fehler;

id inhalt = [NSString stringWithContentsOfURL:   urlEinerDateiencoding:   eineKodierung

error:   &fehler];if (inhalt == nil) {

// Fehlerverarbeitung, hier z. B. Protokollierungauf der Konsole

NSLog(@"Fehler: %@", fehler);}

Zunächst deklarieren Sie einen  NSError-Zeiger – eine Referenz, dienoch auf nichts zeigt –, und dann übergeben Sie die Adresse diesesZeigers an die Methode. Wenn es während der Ausführung derMethode zu einem Fehler kommt, wird an dieser Adresse der Zeigerauf ein passendes  NSError-Objekt gespeichert. Ist die Ausführungder Methode beendet, zeigt  fehler  dann auf das in der Methodeerstellte NSError-Objekt (falls in der Methode eines erstellt wurde).

74 | Kapitel 7: Fehler und Ausnahmen

Page 83: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 83/224

Beachten Sie, dass man den Fehler üblicherweise nicht vom Vor-handensein eines NSError-Objekts ableitet, sondern aus dem Rück-gabewert der Methode, z. B. daraus, dass dieser nicht definiert ist.

NSError-Objekte bieten über die Nachrichten   -code   und   -domainZugriff auf den Fehlercode und die Fehlerdomain. Weitere Infor-mationen werden in einem userInfo-Dictionary gespeichert. EinigeNSError-Hilfsmethoden bieten Zugriff auf standardmäßig im   user

Info-Dict vorhandene Schlüssel.   localizedDescription,   localiz

edFailureReason   und   localizedRecoverySuggestion   liefern Stringsmit zunehmend detaillierteren Beschreibungen des Fehlers,

localizedRecoveryOptions Buttonbeschriftungen für einen NSAlert-Dialog und   recoveryAttempter  ein Delegate-Objekt, das möglicheProgrammaktionen als Reaktion auf den Fehler definiert.

Wenn Sie eigene Fehlerobjekte erstellen wollen, können Sie dieKlassennachricht   +errorWithDomain:code:userInfo   oder die In-stanznachricht –initWithDomain:code:userInfo: nutzen.

Ein Beispiel

Der folgende Code deklariert eine Methode, die im Fehlerfall einNSError-Objekt erstellt und dieses über den Referenzparameterfehler   zurückliefert. Das Dict für den   userInfo-Parameter wirdhier nur vorab definiert, um die Anweisung, die den Fehler definiert,übersichtlicher zu halten:

- (NSString *) antwort: (NSError **) fehler {if ([self frage] == nil) {

id info = @{NSLocalizedDescriptionKey :

@"Leider gibt es keine Antwort!",NSLocalizedRecoverySuggestionErrorKey :

@"Stellen Sie eine ein_beispielFrage!"};

fehler = [[NSError alloc] initWithDomain:@"org.antworten.FrageApp.ErrorDomain"

code: 404userInfo: info];

return nil;} else {

return @"42";}

}

Fehler | 75

Page 84: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 84/224

Abbildung 7-1 zeigt, wie der Dialog aussehen würde, der erschiene,wenn das so erstellte  NSError-Objekt in einer AppKit-Anwendungmit   [NSAlert alertWithError: fehler]   zur Initialisierung eines

Warndialogs verwendet würde.

 Abbildung 7-1: NSError-Warndialog 

NSError-ReferenzDie folgende Aufstellung enthält die wichtigsten NSError-Nachrichten:

- (NSInteger) code

Liefert den domainspezifischen Fehlercode.

- (NSString *) domain

Liefert die Fehlerdomain. Fehler werden in Domains gegliedert,die den verschiedenen Subsystemen zugeordnet sind, die an derAusführung des Programms beteiligt sind. In NSError.h werdendie vier Basisdomains   NSMachErrorDomain   (Kernelebene),NSPOSIXErrorDomain (Unix-Ebene),  NSOSStatusErrorDomain   (Car-bon) und   NSCocoaErrorDomain   (Cocoa) deklariert. Frameworkskönnen zusätzlich ihre eigenen Domains definieren. Wenn Sie

eigene NSError-Objekte nutzen wollen, müssen Sie einen eigenen,eindeutigen Wert für die Domain wählen. Dieser sollte üblicher-weise die Struktur   umgekehrte Internetadresse. App-Name.Error

Domain haben, z. B. de.ich.Informationsvergabe.ErrorDomain.

76 | Kapitel 7: Fehler und Ausnahmen

Page 85: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 85/224

+ (id)errorWithDomain:(NSString *)domain

code:(NSInteger)code

userInfo:(NSDictionary *)dict

Erstellt und liefert ein   NSError-Objekt, das mit den durch dieArgumente angegebenen Werte für die Fehlerdomain, den Feh-lercode und das  userInfo-Dict initialisiert wird. Das Domainar-gument darf nicht nil sein, das userInfo-Argument darf  nil sein.

- (NSString *) helpAnchor

Liefert einen String, der Text enthält, der auf den Abschnitt derSystemhilfe verweist, der angezeigt wird, wenn in einem Alert-

View auf das Hilfesymbol geklickt wird. Im Alert-View wird einHilfesymbol angezeigt, wenn   helpAnchor   einen Wert ungleichnil   liefert. Im   userDict  wird dieser Wert unter   NSHelpAnchor

ErrorKey festgehalten.

- (id)initWithDomain:(NSString *)domain

code:(NSInteger)code

userInfo:(NSDictionary *)dictInitialisiert und liefert ein alloziertes  NSError-Objekt, das mitden durch die Argumente angegebenen Werte für die Fehler-domain, den Fehlercode und das   userInfo-Dict initialisiertwird. Das Domainargument darf nicht  nil sein, das  userInfo-Argument darf  nil sein.

- (NSString *) localizedDescription

Liefert einen String, der eine lokalisierte Beschreibung desFehlers enthält. Diese Daten können auch über den  userInfo-Schlüssel NSLocalizedDescriptionKey abgerufen werden.

- (NSString *) localizedFailureReason

Liefert einen String, der eine lokalisierte Angabe zum Grund desFehlers enthält. Entspricht dem Wert des  userInfo-Schlüssels

NSLocalizedFailureReasonErrorKey.- (NSArray *) localizedRecoveryOptions

Liefert ein Array, das von rechts nach links die lokalisiertenBeschriftungen für die Buttons in einem Warndialog enthält, indem die Fehlerdaten angezeigt werden. Diese Daten werdenüber den Schlüssel   NSLocalizedRecoveryOptionsErrorKey   aus

NSError-Referenz | 77

Page 86: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 86/224

dem  userInfo-Dict abgerufen. Liefert  nil, wenn  userInfo  kei-nen entsprechenden Wert enthält.

- (NSString *) localizedRecoverySuggestion

Liefert einen String, der zusätzliche Textinformationen zumFehler enthält, die z. B. als weitergehende Hinweise oder Fehler-behebungsanweisungen in einem Warndialog geeignet sind.Diese Daten werden über den Schlüssel   NSLocalizedRecovery

SuggestionErrorKey aus dem userInfo-Dict abgerufen.

- (id) recoveryAttempter

Liefert ein Objekt, das Aktionen definiert, die den Wahlmöglich-keiten entsprechen, die dem Benutzer im Warndialog über daslocalizedRecoveryOptions-Array angeboten werden. Das Objektmuss die in   NSError.h   deklarierte   NSObject-Kategorie   NSError

RecoveryAttempting implementieren. Wenn ein NSError in einemWarndialog angezeigt wird und   userInfo  unter dem SchlüsselNSRecoveryAttempterErrorKey ein entsprechendes Objekt enthält,

wird seine   attemptRecoveryFromError:optionIndex:-Methodemit dem Index in   localizedRecoveryOptions   aufgerufen, derdem Button entspricht, der im Dialog gewählt wurde.

-(NSDictionary *) userInfo

Ein Dictionary mit zusätzlichen Informationen, die den Fehlerbeschreiben, und eventuell Objekten, die genutzt werden kön-nen, um nach einem Fehler eine Wiederherstellung zu ver-

suchen. Der am häufigsten verwendete Schlüssel in das   userInfo-Dict ist   NSLocalizedDescriptionKey,der   eine lokalisierteBeschreibung des Fehlers liefert.

AusnahmenObjective-C bietet seit Mac OS X 10.3 eine Ausnahmebehandlungder kanonischen  try/catch/finally-Gestalt. Wie in der Einleitungzu diesem Abschnitt erwähnt, werden diese Strukturen aber andersverwendet als bei anderen Programmiersprachen. Ausnahmen soll-ten nicht zur Behandlung von Fehlern genutzt werden, die zurLaufzeit behoben werden können, sondern nur bei Problemen

78 | Kapitel 7: Fehler und Ausnahmen

Page 87: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 87/224

verwendet werden, die normalerweise zum Abbruch des Pro-gramms führen sollten.

Wenn Sie ARC nutzen, sollten Sie außerdem beachten, dass ARC

unter Objective-C Ausnahmen standardmäßig nicht berücksichtigt(aber unter Objective-C++). Starke Bindungen werden nicht freige-geben, wenn Ausnahmen auftreten. Das heißt: Standardmäßigführen Ausnahmen unter ARC zu Speicherlöchern. Wenn Sie inIhrem ARC-Code Ausnahmen nutzen und behandeln wollen, müs-sen Sie die Compileroption -fobjc-arc-exceptions verwenden, da-mit ARC Ausnahmen berücksichtigt. Das ist standardmäßig nicht

der Fall, da das erhebliche Auswirkungen auf die Laufzeitleistungund den Codeumfang hätte.

Es gibt in Objective-C also eine Ausnahme-behandlung, aber Apple rät Ihnen de facto,diese nicht zu verwenden. Nutzen Sie Ausnah-men, wenn ein Problem zum Abbruch des Pro-

gramms führen sollte (da das Speicherloch dannirrelevant ist); nutzen Sie die Ausnahmebehand-lung, wenn Ausnahmen, die von anderen Pro-grammteilen ausgelöst werden, nicht zum Pro-grammabbruch führen sollen (und vergessen Siedann nicht, ARC-Ausnahmen zu aktivierenbzw. ARC abzuschalten).

Nach diesen Vorbemerkungen: Zur Ausnahmebehandlung nutzenSie die vier Compilerdirektiven   @try,   @catch(),   @finally   und@throw.   @try,   @catch   und   @finally   werden eingesetzt, um eineAusnahmeverarbeitung der kanonischen   try/catch/finally-Struk-tur aufzubauen, z. B.:

@try {

// Code, der Ausnahmen auslosen kann}@catch (NSException *ex) {// Code, der eine auftretende Ausnahme verarbeitet}@finally {// Code, der immer ausgefuhrt wird, unabhangig davon,// ob eine Aufnahme auftrat oder nicht}

Ausnahmen | 79

Page 88: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 88/224

Der   @catch()-Handler muss den Typ von Ausnahmeobjekt ange-ben, den dieser Handler verarbeitet. Dieser kann angegeben wer-den, indem ein Parameter angegeben wird, über den im  @catch()-

Handler auf das mit der Ausnahme verbundene Objekt zugegriffenwerden kann. Wenn der Handler keinen Zugriff auf das mit derAusnahme ausgelöste Objekt benötigt, kann alternativ nur derAusnahmeobjekttyp (z. B. NSString *) angegeben werden.

Es können mehrere @catch()-Handler angegeben werden. Ausnah-me-Handler für speziellere Ausnahmeobjekte sollten Ausnahme-Handlern für allgemeinere Ausnahmeobjekte vorangehen. Es ist

empfehlenswert, die Kette der Ausnahme-Handler mit einem all-gemeinen Handler abzuschließen, der als Typ id angibt.

@catch(NSException *ex) {// Verarbeitet Ausnahmen, mit denen ein NSException-Objekt// verbunden ist}@catch(id) {

// Verarbeitet alle anderen Ausnahmen und fangt das// Ausnahmeobjekt nicht ein}

Die Ausnahmeinformationen werden üblicherweise von NSException-Objekten gekapselt.   NSException-Objekte bieten einige Methoden,mit denen Informationen zur Ausnahme abgerufen bzw. eigene Aus-nahmen erstellt und ausgelöst werden können.

In Objective-C gibt es anders als in Java keine komplexe Hierarchievon Ausnahmeklassen. Ausnahmen werden üblicherweise durchden Namen und die anderen Ausnahmeeigenschaften differenziert.Bei Bedarf können Sie jedoch jederzeit eigene  NSException-Unter-klassen definieren.

Ausnahmen können mit @throw ausgelöst werden oder über eine der

raise-Methoden von  NSException. Mit  @throw  wird ein Objekt alsAusnahmeobjekt ausgelöst. Dieses Objekt kann eine Instanz einerbeliebigen von   NSObject   abgeleiteten Klasse sein, es muss nichtnotwendigerweise eine NSException-Instanz oder eine Instanz einervon   NSException  abgeleiteten Klasse sein. Zum Beispiel wäre Fol-gendes vollkommen zulässig:

@throw @"Dummer Fehler";

80 | Kapitel 7: Fehler und Ausnahmen

Page 89: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 89/224

Wenn Sie Ausnahmeobjekte nutzen, die keine Instanzen vonNSException  oder einer   NSException-Unterklasse sind, müssen Sienatürlich auch Handler nutzen, die die entsprechenden Objekt-

typen abfangen.

Beachten Sie, dass es sein kann, dass Frame-work-Methoden nur NSException-Objekte ab-fangen. Andererseits kann es jedoch sein, dassFramework-Methoden selbst andere Objekt-typen als Ausnahmeobjekt verwenden. Ihrer-seits sollten Sie also bereit sein, Objekte

 jeglicher Art als Ausnahmeobjekt zu berück-sichtigen.

In einem @catch()-Handler kann @throw ohne Argument verwendetwerden, um die aktuelle Ausnahme neu auszulösen.

Ein BeispielDer folgende Code unternimmt etwas, das zur Auslösung einerAusnahme führen kann. Wird eine Ausnahme ausgelöst, wird sievom @catch-Abschnitt verarbeitet, der sie entweder konsumiert (hierindem er auf der Konsole eine Nachricht protokolliert) oder neuauslöst (weil er mit ihr nichts anfangen kann), damit sie von einemübergeordneten Ausnahme-Handler verarbeitet wird.  @finally sorgtdafür, dass, unabhängig davon, ob eine Ausnahme auftrat oder nicht,aufgeräumt wird – auch wenn die abgefangene Ausnahme neu aus-gelöst wird:

// Zunachst wird etwas Unordnung geschaffenBuch *buch = [Bibliothek buchMitName: @"Ulysses"];@try {

// Lost eine Ausnahme aus, wenn eine Grundbedingung

// nicht erfullt istif ([self lustUnlust] < 10)

@throw [NSException exceptionWithName: @"NoBockException"reason: @"…"

userInfo: nil];else

[buch lesen]; // Konnte eine andere Ausnahme auslosen}

Ausnahmen | 81

Page 90: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 90/224

@catch (NSException *ex) {if ([[ex name] isEqualToString: @"NoBockException"])

// Manche Probleme mussen nicht das Ende seinNSLog(@"Lust nur %i", [self lustUnlust]);

else// Eine lesen-Ausnahme hingegen wird neu ausgelost[ex raise];

}@finally {

[buch wegraeumen]; // Hinterher ordentlich aufraumen}

Beachten Sie, dass dieses Beispiel die Ausnah-meverarbeitung genau zu dem Zweck einsetzt,zu dem sie eigentlich nicht eingesetzt werdensollte.

Handler fu r nicht abgefangene Exceptions

Das Foundation-Framework bietet eine Möglichkeit, einen Handlerfür Ausnahmen zu registrieren, die nicht abgefangen wurden. Indiesem Handler können Sie Informationen zur Ausnahme protokol-lieren, bevor das Programm abgebrochen wird.

Der Handler wird mit der Funktion NSSetUncaughtExceptionHandler()

registriert (und kann mit der Funktion   NSGetUncaughtException

Handler()   abgerufen werden).   NSSetUncaughtExceptionHandler()erwartet als Argument einen Zeiger auf eine C-Funktion, die eineNSException-Referenz als Argument erwartet und den Rückgabetypvoid hat.

Der nachfolgende Code definiert die (recht primitive) Handler-Funktion   UncaughtExceptionHandler()   als Top-Level-C-Funktionund registriert diese zu Anfang des Programmcodes mit   NSSet

UncaughtExceptionHandler()   als Handler für nicht abgefangeneAusnahmen:

void UncaughtExceptionHandler(NSException *ex) {NSLog(@"Nicht abgefangene Ausnahme: %@", ex);

}

int main() {

82 | Kapitel 7: Fehler und Ausnahmen

Page 91: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 91/224

@autoreleasepool {NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);// …

}

return 0;}

NSException-ReferenzDie folgende Aufstellung enthält die wichtigsten NSException-Nach-richten:

- (NSArray *)callStackReturnAddresses

Liefert ein Array mit den Rücksprungadressen zum Callstackder Ausnahme in aufsteigender Reihenfolge (d. h., das ersteElement ist die Position, an der die Ausnahme auftrat).

- (NSArray *)callStackSymbols

Liefert ein Array mit den Daten des Callstacks.

+ (NSException *)exceptionWithName:(NSString *)name

reason:(NSString *)reason

userInfo:(NSDictionary *)userInfo

Erzeugt und liefert ein  NSException-Objekt mit den angegebe-nen Werten für  -name und  -reason. Als letzter Parameter kannein userInfo-Dictionary angegeben werden.

– (id)initWithName:(NSString *)namereason:(NSString *)reason

userInfo:(NSDictionary *)userInfo

Initialisiert ein alloziertes  NSException-Objekt mit den angege-benen Werten für -name, -reason. Als letzter Parameter kann einuserInfo-Dictionary angegeben werden.

- (NSString *)name

Liefert den (eindeutigen) Namen der Ausnahme.

+(void)raise: (NSString *)name format:(NSString *)format, ...

+(void)raise: (NSString *)name format:(NSString *)format

arguments:(va_list)args

Diese beiden Klassenmethoden lösen unmittelbar eine Ausnahmeaus, mit der ein Name und ein Grund, aber kein  userInfo-Dict

NSException-Referenz | 83

Page 92: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 92/224

verbunden ist. Das erste Methodenargument ist ein NSString, derzum Namen der  NSException wird, das zweite ein Formatstring,der für den Aufbau des Werts genutzt wird, den  -reason liefert.

Der Formatstring wird mit den Argumenten gefüllt, die (bei derersten Form) als kommaseparierte Liste nach dem Formatstringoder (bei der zweiten Form) über eine va_list angegeben werden.

-(void)raise

Löst das Ausnahmeobjekt aus, dem diese Nachricht gesendetwird. Das ist die Methode, die immer aufgerufen wird, wennirgendwie eine Ausnahme ausgelöst wird.

- (NSString *)reason

Liefert einen Text, der üblicherweise den Grund für das Auf-treten der Ausnahme angeben sollte.

- (NSDictionary *)userInfo

Liefert das Dict mit den Daten und Informationen zur Ausnah-me.

84 | Kapitel 7: Fehler und Ausnahmen

Page 93: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 93/224

KAPITEL 8

NSObject

NSObject ist die Basisklasse, die von Apples Plattformen genutzt wird.Sie bestimmt die Grundstruktur aller Klassen, die Sie bei der Pro-grammierung mit Objective-C nutzen bzw. schreiben, und damit dieInteraktionsschnittstelle aller Objekte, mit denen Sie arbeiten.

Alle (fast alle) Klassen der Cocoa-Bibliotheken, die Sie bei derObjective-C-Programmierung nutzen werden, sind mittelbar oderunmittelbar Unterklassen von NSObject und erben die dort definier-ten Felder, Eigenschaften und Methoden. Weil diese so die Grund-struktur von Objective-C-Objekten bestimmen, ist die   NSObject-Schnittstelle von elementarer Bedeutung bei der Programmierung

in Objective-C.Anders als die Basisklassen von Sprachen wie Java oder C# hat dieBasisklasse von Objective-C eine eher komplexe Schnittstelle (dieunter Mac OS X über 200 Nachrichten umfasst und unter iOS nurein paar weniger). Sie bietet unter anderem Interaktionsmöglich-keiten für die hier aufgeführten Aufgabenbereiche:

• Klassen- und Objektinitialisierung• Erstellen, Kopieren und Zerstören von Objekten

• Identifikation von Klassen und Prüfen der Eigenschaften vonKlassen

• Senden, Weiterleitung und Auflösen von Nachrichten

• Objektarchivierung

| 85

Page 94: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 94/224

• Klassenattribute

• Scripting

In den nachfolgenden Abschnitten werden wir Ihnen eine Einfüh-rung in die Operationen geben, die Ihnen die NSObject-Schnittstellebeim Umgang mit den Instanzen ihrer Klassen bietet. Wir werdenuns dabei auf die Aufgabenbereiche konzentrieren, die unter MacOS X und unter iOS unterstützt werden. Eine Referenz zu allenNachrichten, die in diesen Abschnitten vorgestellt und erwähntwerden, finden Sie gegen Ende des Buchs in Kapitel 16, NSObject-Referenz.

Bei Objective-C wird die Basisklasse anders als bei z. B. Java nichtvon der Sprache vorgegeben. Das bedeutet, wenn Sie wollen, kön-nen Sie eine Klassenhierarchie schaffen, die auf einer eigenen Basis-klasse basiert.

86 | Kapitel 8: NSObject

Page 95: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 95/224

KAPITEL 9

Objektlebenszyklus

Wenn Sie sich ein Objekt beschaffen, muss im Hintergrund eineganze Menge geschehen. Kommen Sie von einer Programmierspra-che wie Java, werden Sie sich darüber wahrscheinlich wenig Gedan-ken machen. Sie sagen new Objekt() und erhalten ein neues Objekt,frisch initialisiert und einsatzbereit. Vielen Dank, Runtime. Undwenn Sie es nicht mehr brauchen, vergessen Sie einfach, dass Sie es

 je erstellt haben – im Vertrauen darauf, dass die Garbage Collectionschon hinter Ihnen aufräumen wird.

Da haben wir einige garstige Überraschungen für Sie parat: InObjective-C gibt es keinen new-Operator, keine Konstruktoren undauch eine Garbage Collection ist nicht (mehr) verfügbar. Objective-C-Klassen müssen folglich eigene Features anbieten, die sich mitdiesen Aufgaben befassen.

Konventionsgemäß wird dazu eine Gruppe von Methoden genutzt,die von der Framework-Basisklasse NSObject deklariert und imple-mentiert werden:

•   +initialize

•   +alloc

•   +new•   -init

•   -dealloc

Alle Klassen (die Teil der   NSObject-Hierarchie sind) erben dieseMethoden und nutzen sie zur Allozierung, Initialisierung und Deal-lozierung von Objekten. Diese Implementierungen in   NSObject

| 87

Page 96: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 96/224

bestimmen, wie der Speicher für Objekte bereitgestellt wird undwas unternommen wird, wenn er wieder freigegeben werden muss.Deswegen haben sie einen ganz wesentlichen Anteil daran, wie sich

die Arbeit mit Objekten in Objective-C gestaltet – konfigurierensozusagen einen grundlegenden Aspekt der Sprache. Wenn Sieeigene Klassen schreiben, die eine spezielle Initialisierung verlangen,sollten Sie die Grundaufgaben stets an diese Basisversionen delegie-ren und die eigenen Einrichtungen in den entsprechenden Metho-den bereitstellen.

Objekte erstellenDie Erstellung von Objekten ist in Objective-C ein zweistufigerProzess. Zunächst wird der Speicher alloziert, dann werden dieFelder initialisiert. Von der Allozierung erhalten Sie einen Zeigerauf einen Speicherbereich, in dem das vorinitialisierte Objekt ge-speichert ist. Mit der Initialisierung initialisieren Sie die Felder des

neuen Objekt, wie es für die jeweilige Klasse erforderlich ist.Die Allozierung erfolgt mit einer  +alloc-Nachricht, die Initialisie-rung mit einer -init-Nachricht. Wie Sie an den Vorzeichen erken-nen können, werden die beiden Nachrichten an unterschiedlicheEmpfänger gesendet:   +alloc  an die Klasse,  -init  an die Klassen-instanz:

id objekt = [Klasse alloc];objekt = [objekt init];

Beide Nachrichten liefern ein Objekt des Typs  id. Das von  +alloc

gelieferte Objekt ist noch nicht verwendungsfähig und muss erstmit  -init  initialisiert werden. (Beispielsweise würde  NSLog(@"%@",

[NSString alloc])   zu einem Laufzeitfehler führen, währendNSLog(@"%@", [[String alloc] init] problemlos läuft.)

Da der von   -init   gelieferte Zeiger nicht mit dem identisch seinmuss, der von +alloc geliefert wurde, sollten Sie immer den Rück-gabewert von   -init   festhalten. Wenn Sie das nicht tun, kann essein, dass Ihr Empfänger nicht korrekt initialisiert wird. Zum Bei-spiel:

88 | Kapitel 9: Objektlebenszyklus

Page 97: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 97/224

id alloziert = [NSString alloc];id initialisiert = [alloziert init];if (alloziert != initialisiert) {

NSLog(@"Ungleich!");

}

Dieser Code gibt »Ungleich!« aus, weil der Zeiger, den -init liefert,auf einen anderen Speicherbereich als den zeigt, den +alloc lieferte.Üblicherweise werden die +alloc- und -init-Nachrichten deswegenverkettet:

id objekt = [[Klasse alloc] init];

Alternativ können Sie der Klasse auch die  +new-Nachricht senden,die nichts anderes als ein Alias für [[Klasse alloc] init] ist:

id objekt = [Klasse new];

Allozierung

+alloc hat eine sehr wichtige Aufgabe: Es muss die interne Struktureines Objekts im Speicher einrichten, bevor dieses initialisiert wird.+alloc ist allerdings nicht nur für die Speicherbeschaffung verant-wortlich. Es sorgt außerdem dafür, dass der Referenzzähler für dasObjekt auf eins gesetzt wird, dass das  isa-Feld auf die Klasse desObjekts gesetzt wird und dass alle Felder des Objekts auf 0 bzw.den äquivalenten Wert für den entsprechenden Datentyp initiali-siert werden. Erst die Initialisierung mit einer Initialisierungsnach-richt macht das mit +alloc allozierte Objekt verwendbar.

Überschreiben Sie   alloc   nicht. Alle eigenenInitialisierungsaufgaben sollten Sie in Initiali-sierungsmethoden stecken.

Objektinitialisierung

Die Aufgabe der   -init-Methode ist mit der eines Konstruktorsvergleichbar – sie liefert eine konkrete, korrekt initialisierte Instanzder Klasse. Die   -init-Methode von   NSObject  macht nichts. WennIhre Klassen eine spezielle Initialisierung verlangen, müssen Sie ei-gene Initialisierungsmethoden schreiben. Sie können parameterlose

Objekte erstellen | 89

Page 98: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 98/224

-init-Methoden schreiben, die die   -init-Methode von   NSObject

überschreiben, und Sie können Initialisierungsmethoden schreiben,die Parameter erwarten.

Es gibt zwei wesentliche Unterschiede zwi-schen den Initialisierungsmethoden von Ob- jective-C und den Konstruktoren von bei-spielsweise Java:

• Konstruktoren haben keine Rückga-bewerte.

• Konstruktoren werden nicht vererbt.

Eine Initialisierungsmethode sollte drei Kriterien genügen:

1. Der Methodenname beginnt mit init.

2. Die Methode liefert den Wert von self zurück.

3. Der Rückgabewert der Methode hat den Typ id.

Die Struktur von Objective-C-Methodennamen sorgt dafür, dassInitialisierungsmethoden, die Parameter erwarten, jeweils unter-schiedliche Namen haben. Die Namen dieser Methoden solltenklar zum Ausdruck bringen, dass es sich um Initialisierungsmetho-den handelt. Beispielsweise könnte eine   Haustier-Klasse die Init-Methoden   -initMitArt,   -initMitArt:name:,   -initMitArt:name:al

ter bieten.

Anders als bei den Konstruktoren andererSprachen wird die Gestalt der Initialisierungs-methoden nicht von der Syntax vorgegeben,sondern allein durch Konventionen geregelt.Es ist wichtig, dass Sie sich an diese Konven-tionen halten.

Designierte Initialisierer

Wie bei Konstruktoren ist es wichtig, dass alle   Schichten   IhrerObjekte korrekt und in der erforderlichen Reihenfolge initialisiertwerden. Ihre Klassen müssen stets sicherstellen, dass ihre Initialisie-

90 | Kapitel 9: Objektlebenszyklus

Page 99: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 99/224

rungsmethoden an den richtigen Punkten die richtige Initialisie-rungsmethode der Elternklasse aufrufen, damit von der Basisklasseausgehend die Oberklassenschichten des Objekts initialisiert wer-

den, bevor die speziellen Initialisierungsschritte der neuen Klassezur Anwendung kommen. Kurz: Der erste Schritt einer ihrer Ini-tialisierungsmethoden muss sein, die richtige Initialisierungs-methode der jeweiligen Elternklasse aufzurufen.

Wenn Ihre Klasse mehrere Initialisierer hat, sollte sie einen  desig-nierten Initialisierer  haben. Als designierten Initialisierer bezeichnetman unter Objective-C einen Initialisierer, der einen Initialisierer

der Elternklasse aufruft. Dieser  vorgezogene  Initialisierer ist in derRegel der spezifischste Initialisierer, der also, der die meisten Para-meter erwartet. Alle anderen Initialisierer sollten diesen designiertenInitialisierer aufrufen.

Schauen wir uns das anhand eines Beispiels an:

#import <Foundation/Foundation.h>

@interface Tier : NSObject@property NSString *art;- (id)initMitArt:(NSString *)art;@end

@interface Haustier : Tier@property NSString *name;@property NSUInteger *alter;- (id)initMitArt:(NSString *)art

name:(NSString *)name;- (id)initMitArt:(NSString *)art

name:(NSString *)namealter:(NSUInteger *)alter;

@end

Tier definiert den Initialisierer -initMitArt:, der folglich auch derdesignierte Initialisierer sein muss.   Haustier   definiert die Initiali-

sierer   -initMitArt:name:   und   -initMitArt:name:alter.   -initMitArt:name:alter: wird der designierte Initialisierer sein, weil er derspezifischste Initialisierer ist. Wenden wir uns nun den Implemen-tierungen zu:

@implementation Tier- (id)init {

return [self initMitArt: @"Unbekannt"];

Objekte erstellen | 91

Page 100: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 100/224

}- (id)initMitArt:(NSString *)art {

if (self = [super init]) {self->_art = art;

} return self;}@end

Tier implementiert  -initMitArt: als designierten Initialisierer. Eindesignierter Initialisierer hat stets zwei Aufgaben:

• Er setzt self auf den Wert, den ihm der designierte Initialisie-

rer der Oberklasse liefert.• Er initialisiert die für Instanzen dieser Klasse spezifischen Ivars

oder Eigenschaften.

Außerdem überschreibt   Tier   den designierten Initialisierer derOberklasse, hier den vertrauten   -init-Initialisierer von   NSObject.Beachten Sie, dass in der   -init-Überschreibung nicht die über-

schriebene -init-Version aufgerufen wird, sondern der designierteInitialisierer der Klasse selbst,  -initMitArt, der allein dafür verant-wortlich ist, den Oberklasseninitialisierer aufzurufen.

Die Implementierungen der Initialisierer der Unterklasse  Haustier

greifen dann auf die Initialisierer von Tier zurück:

@implementation Haustier

- (id)initMitArt:(NSString *)art {return [self initMitArt: art name: @"Namenlos" alter: 0];}- (id)initMitArt:(NSString *)art

name:(NSString *)name {return [self initMitArt: art name: name alter: 0];

}- (id)initMitArt:(NSString *)art

name:(NSString *)name

alter:(int) alter{if (self = [super initMitArt: art]) {

self->_name = name;self->_alter = alter;

}return self;

}@end

92 | Kapitel 9: Objektlebenszyklus

Page 101: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 101/224

Wie  Tier  überschreibt  Haustier  den designierten Initialisierer derOberklasse. Tier überschreibt  -init, den designierten Initialisierervon NSObject, Haustier überschreibt -initMitArt:, den designierten

Initialisierer von Tier. Das stellt sicher, dass ein Aufruf des jeweili-gen Initialisierers auf einer Instanz von Tier respektive Haustier einvernünftiges Ergebnis liefert.

Beide überschreibenden Initialisierer rufen nicht den entsprechen-den Initialisierer der Elternklasse auf, sondern delegieren wie alleanderen  gewöhnlichen   Initialisierer die Arbeit an den designiertenInitialisierer der eigenen Klasse. Nur der designierte Initialisierer,

hier -initMitArt:name:alter: ruft über super den designierten Ini-tialisierer der Eltern Klasse auf. Alle anderen Initialisierer delegierendie Initialisierung mit einem Aufruf auf   self  an den designiertenInitialisierer.

Diese Vorgehensweise sorgt dafür, dass die Initialisierer eine sau-bere Kette bilden und der Aufruf aller Initialisierer, auch aller

Oberklasseninitialisierer, immer ordentlich initialisierte Objekte lie-fert. Würde auf   Haustier init  aufgerufen, erhielten Sie beispiels-weise ein Haustier mit der Art »Unbekannt«, dem Namen »Namen-los« und dem Alter 0.

Haustier hat keine init-Methode, also kommt die geerbte von Tier

zum Einsatz. Diese ruft auf   self -initMitArt:   mit dem Wert@"Unbekannt   auf. Da   self   hier ein   Haustier-Objekt ist, wird die

-initMitArt:-Methode von   Haustier   aufgerufen, die wieder auf self  mit den Werten  @"Unbekannt",  @"Namenlos"  und  0  den desig-nierten Initialisierer   -initMitArt:name:alter:   aufruft. Dieser ruftauf der Elternklasse mit dem Argument  @"Unbekannt den designier-ten Initialisierer   -initMitArt:   auf, setzt   self   auf den Wert, dendieser Initialisierer liefert, und richtet dann auf  self die Werte deranderen Felder ein.

Objekte erstellen | 93

Page 102: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 102/224

Regeln fu r eine konsistenteInitialisierungsstruktur

Eine konsistente Initialisierungsstruktur für Ihre Klassen erhaltenSie, wenn Sie die folgenden drei Grundregeln im Blick halten:

1. Ihre Klasse sollte einen designierten Initialisierer haben, derden designierten Initialisierer der Elternklasse aufruft (Nach-richt an super).

2. Ihre Klasse sollte den designierten Initialisierer der Oberklasse

überschreiben, der den designierten Initialisierer der neuenKlasse aufruft (Nachricht an self).

3. Alle anderen Initialisierer einer Klasse sollten den designiertenInitialisierer aufrufen (Nachricht an self).

Initialisierer und Fehler

Beachten Sie außerdem das  if(self = [super init])-Muster in dendesignierten Initialisierern. Da Initialisierungsmethoden einenRückgabewert haben, können sie im Unterschied zu Java-Kons-truktoren eventuelle Fehler über den Rückgabewert signalisieren.Die Initialsierer liefern immer  self   zurück, aber wenn   self  nichtrichtig initialisiert werden konnte, ist  self nil. Die Semantik des

nil-Werts macht ihn zu einem geeigneten Kandidaten für denRückgabewert für den Fall, dass ein Objekt nicht initialisiert werdenkonnte. Das können Sie auch nutzen, wenn Ihre Initialisierungs-methoden komplexere Operationen vornehmen, bei denen es zuFehlern kommen kann. Wenn Ihre Initialisierungsmethode Datenaus dem Netzwerk lesen muss, aber kein Netzwerk verfügbar ist,liefern Sie z. B. also einfach nil.

Klasseninitialisierung

Die Laufzeitumgebung sorgt dafür, dass jeder Klasse, bevor sie odereine ihrer Unterklassen genutzt wird, einmal die +initialize-Nach-richt gesendet wird. Es ist garantiert, dass Elternklassen diese Nach-richt vor ihren Kindklassen erhalten. Wenn eine Klasse nicht zum

94 | Kapitel 9: Objektlebenszyklus

Page 103: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 103/224

Einsatz kommt (direkt und indirekt über eventuelle Unterklassen),erhält sie auch keine +initialize-Nachricht.

+initialize   bietet Klassen eine Möglichkeit, ihre Laufzeit-

umgebung einzurichten, bevor sie verwendet werden. Eine+initialize-Methode ist beispielsweise ein geeigneter Ort zur Ein-richtung von Klassenvariablen.

Beachten Sie jedoch, dass einer Klasse +initialize zwar nur einmaldirekt gesendet wird, eine Klasse die Nachricht aber dennoch mehr-fach erhalten kann. Wenn eine Klasse keine eigene   +initialize-

Implementierung anbietet, wird in der Vererbungshierarchie auf-gestiegen, bis eine Implementierung gefunden wird. Deswegensollten Sie in  +initialize-Methoden immer prüfen, ob die Nach-richt tatsächlich für diese Klasse gedacht ist. Dazu können Sie dasfolgende Muster nutzen:

@implementation Familie+ (void)initialize {

// Pruft, ob self tatsachlich diese Klasse istif (self == [Familie class]) {nochErlaubteKinder = MAX_KINDER;

}}

Verketten Sie  initialize-Nachrichten nicht.Da die Laufzeitumgebung bereits dafür sorgt,

dass Elternklassen diese Nachricht vor Kind-klassen erhalten, ist es nicht erforderlich, eineempfangene initialize-Nachricht an die El-ternklasse weiterzuleiten. Eine Verkettung voninitialize-Nachrichten würde das Musteraushebeln und dazu führen, dass initializedoch mehrfach an eine Klasse gesendet wird.

Objekte kopierenWenn Sie einer Variablen  a des Typs  int  den Wert einer anderenVariablen b des Typs int  zuweisen, wird der Wert an der Speicher-stelle für b in die Speicherstelle für a kopiert. Ändern Sie später denWert von b, hat das keine Auswirkungen auf den Wert von  a:

Objekte kopieren | 95

Page 104: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 104/224

Page 105: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 105/224

Diese beiden Methoden werden in den Protokollen   NSCopying   re-spektive NSMutableCopying deklariert. Keins davon wird von NSObject

übernommen. Es gibt also keine Standardimplementierung von -copy

oder   -mutableCopy, die Ihre Klassen erben würden. Der Versuch,einem Objekt, dessen Klasse das entsprechende Protokoll nicht über-nimmt, eine dieser Nachrichten zu senden, führt zu einem Fehler.Wenn Ihre Objekte das Kopieren unterstützen sollen, muss dieentsprechende Klasse die entsprechenden Protokolle übernehmen.

Dass es zwei Protokolle und zwei Methoden gibt, ist für Sie nurinteressant, wenn es veränderliche und unveränderliche Varianten

Ihrer Klassen gibt, wie beispielsweise bei   NSArray   und   NSMutableArray. Gewöhnlich werden Sie bei Ihren Klassen nur   NSCopying

adoptieren und   -copyWithZone   implementieren müssen, um dieInstanzen dieser Klasse kopierbar zu machen. Nur wenn IhreKlassen veränderliche und unveränderliche Werte unterstützen,müssen Sie beide Protokolle implementieren. -copyWithZone: solltedann eine unveränderliche Kopie liefern, -mutableCopyWithZone eine

veränderliche.

Ist der Unterschied zwischen veränderlichenund unveränderlichen Instanzen für IhreKlasse irrelevant, nutzen Sie stets nur   NSCopying.

Kopiermethoden implementieren

Wenn die Oberklasse   NSObject   ist (oder eine andere Klasse, dieNSCopying   weder direkt noch indirekt implementiert), wird eineneue Objektinstanz erstellt, deren Felder dann mit den entsprechen-den Werten des Originals gefüllt werden. Schauen wir uns das

anhand unserer Tier-Klasse an:@implementation Tier-(id)copyWithZone:(NSZone *)zone {

Tier *kopie = [[[self class] alloc] init];kopie.art = self.art;return kopie;

}@end

Objekte kopieren | 97

Page 106: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 106/224

Wie in einer Initialisierungsmethode sollten Sie auch in Kopier-methoden zur Instanzallozierung nicht den statischen Klassen-namen verwenden, sondern das über   self   abgerufene Klassen-

objekt, damit die Klasse bei einem Aufruf über eine Unterklasserichtig initialisiert wird.

Wenn die Oberklasse NSCopying implementiert, wird der Oberklas-senteil durch eine Delegation der Nachricht an  super   initialisiert,wie Sie es hier am Beispiel der Klasse Haustier sehen:

@implementation Haustier-(id)copyWithZone:(NSZone *)zone {

Haustier *kopie = [super copyWithZone:zone];kopie.name = self.name;kopie.alter = self.alterreturn kopie;

}

Beachten Sie, dass wir direkt   [super copyWithZone:zone]  aufrufenund nicht   [super copy]   nutzen, da das zu einer Endlosschleife

führen würde.

Tiefe und flache Kopien

Beim Kopieren müssen Sie entscheiden, ob Sie eine flache oder einetiefe Kopie erstellen wollen. Bei einer flachen Kopie zeigen dieObjektinstanzvariablen der Kopie auf dieselben Objekte wie die

Objektinstanzvariablen des Originals. Bei einer tiefen Kopie werdenauch Kopien der Objektinstanzvariablen erstellt.

Das Beispiel im letzten Abschnitt hat nur eine flache Kopie erstellt.(Lassen Sie sich von der Unveränderlichkeit von  NSString nicht zuder Annahme verleiten, dass das hier keine Rolle spielt. Den  name-und  art-Eigenschaften können auch Instanzen der veränderlichenUnterklasse NSMutableString zugewiesen werden.) Eine tiefe Kopievon Tier würden Sie wahrscheinlich folgendermaßen erstellen:

-(id)copyWithZone:(NSZone *)zone {Tier *kopie = [[[self class] alloc] init];kopie.art = [self.art copy];return kopie;

}

98 | Kapitel 9: Objektlebenszyklus

Page 107: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 107/224

Beachten Sie jedoch, dass dieser Code zwar wahrscheinlich leistet,was er leisten soll, trotzdem aber nicht tut, was Sie vielleichterwarten. Die -copy-Methode von NSString liefert self zurück und

keine Kopie. Wenn  self.art  tatsächlich ein  NSString-Objekt refe-renziert, zeigen self.art und  kopie.art also auf das gleiche Objekt – was, da es tatsächlich unveränderlich ist, kein Problem sein sollte.Wenn self.art ein NSMutableString-Objekt referenziert, wird hin-gegen eine unabhängige, unveränderliche Kopie erstellt – genau wiewir es haben wollten.

Wenn Sie tatsächlich eine eigenständige Kopie eines   NSString-

Objekts erstellen wollen, müssen Sie tricksen. Sie können z. B.zunächst eine veränderliche Kopie erstellen, von der Sie dann eineunveränderliche Kopie erstellen:

[[self.art mutableCopy] copy];

So erhalten Sie in beiden Fällen, bei einem   NSString   und einemNSMutableString, eine eigenständige, unveränderliche Kopie. (Das

ist ein spezielles Problem des  NSString-Klassenclusters, das andereFramework-Objekte nicht aufweisen.)

NSObject.h-Header definieren außerdem eineFunktion namens   NSCopyObject(), die eineflache Kopie eines beliebigen Objekts erstellt.Diese Funktion ist seit Mac OS X 10.8 und iOS

6 veraltet, und Ihr Einsatz ist unter ARC auchin früheren Versionen nicht gestattet. ApplesDokumentation warnt explizit, dass der Ein-satz dieser Funktion gefährlich ist. Insbeson-dere von ihrer Verwendung bei der Implemen-tierung der Kopiermethoden wird abgeraten.Nutzen Sie diese Funktion also nicht.

ObjektvernichtungWenn ein Objekt nicht mehr benötigt wird, sorgt die Runtimedafür, dass der mit ihm verbundene Speicher freigegeben wird.Wie das erfolgt, ist davon abhängig, welche Speicherverwaltungs-technologie zum Einsatz kommt. Bei der Speicherverwaltung mit

Objektvernichtung | 99

Page 108: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 108/224

ARC sorgt die Runtime dafür, dass Objekte zur geeigneten Zeit die-dealloc-Nachricht erhalten. Bei der manuellen Speicherverwal-tung mussten Sie das teilweise selbst übernehmen.   -dealloc  gibt

dann den Speicher frei, der mit dem Objekt verknüpft ist

1

.Vor ARC gehörte es zu den Grundaufgaben aller Objective-C-Pro-grammierer,   -dealloc-Implementierungen anzubieten, in denenIvars freigegeben wurden, bevor die   -dealloc-Nachricht an dieOberklasse weitergeleitet wurde. Teile davon sind unter ARC un-nötig, andere verboten. Ein Beispiel zur Verwendung von -dealloc

finden Sie in Kapitel 10, Speicherverwaltung .

1 Unter der veralteten Garbage Collection erhielt das Objekt stattdessen eine-finalize-Nachricht.

100 | Kapitel 9: Objektlebenszyklus

Page 109: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 109/224

KAPITEL 10

Speicherverwaltung

Wenn Sie von einer Programmiersprache wie Java kommen, werdenSie sich wahrscheinlich fragen, warum Sie sich mit so etwas wie derVerwaltung des Speichers befassen müssen. »Ich lege meine Varia-blen an, weise ihnen Werte zu und arbeite mit ihnen; und wenn ichdie Werte nicht mehr brauche, wird das System schon wissen, wases mit ihnen anfangen soll.« So einfach ist das bei Objective-C nicht.

Was Speicherverwaltung istIhre Programme fordern Speicher, andere Programme fordern Spei-cher, aber der Speicherplatz, den das System bietet, ist beschränkt.Das kann nur gutgehen, wenn der Speicher, den ein Programmbenötigt, irgendwann wieder freigegeben wird.

Es gibt verschiedene Arten von Speicher: Speicher, der den jeweili-gen Ausführungseinheiten (Methode, Funktion oder Blöcken) zu-geordnet ist, und Speicher, der für das gesamte Programm verfügbarist. Die erste Art Speicher ist der Stack (Stapel), die zweite der Heap(Halde). Der Stack wird immer automatisch verwaltet. Wenn eineneue Ausführungseinheit gestartet wird, wird auf dem Stack einneuer  Stack-Frame  speziell für diese Ausführungseinheit angelegt.Ist die Ausführung jener Einheit abgeschlossen, wird dieser Framevom Stack genommen und entfernt, und mit ihm verschwinden alledort gespeicherten Werte. Aus diesem Grund brauchen Programmeeine zweite Art Speicher, den Heap, der nicht an eine Ausführungs-einheit gebunden ist und Daten festhalten kann, die von mehrerenProgrammkomponenten benötigt werden.

| 101

Page 110: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 110/224

Stack und Heap unterscheiden sich aber auch in Bezug auf dieDaten, die dort gespeichert werden. Bei den meisten Programmier-sprachen ist es so, dass auf dem Stack nur Werte gespeichert

werden, die immer eine festgelegte Menge Speicher benötigen, ints,floats oder  chars beispielsweise. Auf dem Heap hingegen werdenDaten gespeichert, deren Größe vorab nicht festgelegt ist, wie es beiden meisten Objekttypen der Fall ist. Wenn wir von Speicherver-waltung reden, meinen wir damit also die Verwaltung der Objekt-daten auf dem Heap.

Diese Speicherverwaltung kann ganz unterschiedlicher Art sein. Sie

kann vollkommen automatisch ablaufen, ohne dass der Program-mierer dazu einen einzigen Handschlag unternehmen muss, wie beiSprachen mit einer Garbage Collection. Sie kann aber auch voll-kommen manuell erfolgen wie in C, wo der Programmierer den zuverwendenden dynamischen Speicher aufs Byte genau anfordernund wieder freigeben muss. Objective-C unterstützt zwei Speicher-verwaltungstechnologien, die einen Mittelweg zwischen diesen bei-

den Extremen einschlagen.

Speicherverwaltungstechnologienunter Objective-CDie von Objective-C genutzten Speicherverwaltungstechnologien

sind referenzzählungsbasiert, d. h., allen Objekten ist ein Referenz-zähler zugeordnet, der anzeigt, wie viele Benutzer eines Objekts esgibt. Gibt es keine Benutzer mehr, wird das Objekt gelöscht.

Der ursprüngliche Objective-C-Speicherverwaltungsmechanismus,die manuelle Referenzzählung, erfordert, dass der Entwickler sig-nalisiert, ob ein Objekt aufbewahrt werden soll bzw. dass ein

Objekt gelöscht werden kann. In den letzten Jahren hat man ver-sucht, diesen Prozess mit anderen Technologien stärker zu auto-matisieren. Zunächst wurde mit Objective-C 2.0 eine GarbageCollection (kurz GC) eingeführt, die unter Mac OS X unterstütztwurde, von iOS hingegen nicht. 2011 wurde dann das sogenannteAutomatic Reference Counting, kurz ARC, eingeführt. ARC nimmtdem Programmierer große Teile der Arbeiten ab, die bei der Spei-

102 | Kapitel 10: Speicherverwaltung

Page 111: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 111/224

cherverwaltung anfallen. Anders als die GC wird ARC von Mac OS X und iOS unterstützt.1 Informationen zu den Speicherverwal-tungstechnologien und ihrer jeweiligen Unterstützung bei den Be-

triebssystem- und Entwicklungswerkzeugversionen finden Sie inTabelle 10-1:

Tabelle 10-1: ARC und GC-Unterstützung 

ARC GC

Mac OS X ab 10.6 (10.7) 10.5 – 10.7

iOS ab 4.0 (5.0) x

Xcode ab 4.2 3.0 – 4.4

Seit Mac OS X 10.8 gilt die Garbage Collection als veraltet. Appleempfiehlt ARC nicht nur für neue Projekte, sondern rät auch, alteProjekte auf ARC umzustellen, und bietet in seinen Entwicklungs-werkzeugen Tools, die die Umstellung eines auf manueller Refe-renzzählung oder Garbage Collection basierenden Projekts auto-

matisieren. Der Garbage Collection-Mechanismus wird in diesemBuch deswegen nicht weiter erläutert.

ARC und die (seit Einführung von ARC auch MRC abgekürzte)manuelle Referenzzählung basieren darauf, dass mit Objekten einsogenannter  Referenzzähler   verbunden ist, der festhält, wie vieleBenutzer ein Objekt hat, und signalisiert, ob ein Objekt nochbenötigt wird. Zeigt dieser an, dass ein Objekt nicht mehr benötigt

wird, wird es aus dem Speicher gelöscht. Beide Technologien ver-langen deswegen, dass der Code, der mit Objekten arbeitet, sig-nalisiert, dass er ein Objekt benötigt bzw. nicht mehr benötigt.

Bei der manuellen Referenzzählung ist der Programmierer selbst fürdie Aufbewahrung und Freigabe der Objekte verantwortlich, mitdenen er arbeitet. Objective-C stellt dazu Nachrichten bereit, mit

denen der Referenzzähler gesteuert, d. h. heraufgesetzt oder ver-mindert werden kann. Diese muss der Programmierer so nutzen,dass die Objekte, mit denen er arbeitet, so lange erhalten bleiben,wie er sie benötigt, und gelöscht werden, sobald er sie nicht mehrbenötigt.

1 Beachten Sie, dass bei ARC vor Mac OS X 10.7 und iOS 5 keine schwachenReferenzen unterstützt werden.

Speicherverwaltungstechnologien unter Objective-C | 103

Page 112: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 112/224

Bei der automatischen Referenzzählung ermittelt das System auf Basis der Nutzung der Referenz weitgehend automatisch, ob dasvon der Referenz referenzierte Objekt weiterhin aufbewahrt werden

muss bzw. freigegeben werden kann. Der Programmierer muss dazubei der Deklaration seiner Eigenschaften, Felder und Variablen nurangeben, wie bindend die jeweiligen Referenzen für die Objekte seinsollen, die von ihnen referenziert werden.

Eins der Probleme, die beide Technologien lösen müssen, ist dieÜbergabe der Verantwortung für ein Objekt an eine andere Pro-grammeinheit. Eine Methode kann nichts mehr tun, nachdem sie

einen Wert zurückgegeben hat. Wenn eine Methode ordentlichhinter sich aufräumen will, muss sie die von ihr genutzten Objektealso freigeben, bevor sie endet. Das gilt auch für Objektreferenzen,die einen Rückgabewert darstellen. Dann würde das entsprechendeObjekt aber bereits gelöscht, nachdem die Methode es freigegebenhat, ohne dass der aufrufende Code überhaupt die Möglichkeiterhält, selbst die Verantwortung für seine Aufbewahrung zu über-

nehmen. Dieses Problem wird mit sogenannten Auto-Release-Poolsgelöst. Das sind spezielle Speicherstrukturen, die Objekte kurze Zeitam Leben halten – garantiert so lange, dass eine andere Programm-einheit die Verantwortung dafür übernehmen kann.

ARC (Automatic Reference Counting)Mit dem Automatic Reference Counting versucht Apple, Objec-tive-C eine Speicherverwaltungstechnologie zu spendieren, die fürden Programmierer ähnlich einfach und sicher zu verwenden ist wieeine Garbage Collection, ohne dabei die Nachteile in Kauf nehmenzu müssen, die eine solche mit sich bringen kann. Anders als eineGarbage Collection, die laufzeitbasiert ist, ist ARC eine Compiler-einrichtung. Der Compiler analysiert den Gebrauch eines Objektsund generiert automatisch die erforderlichen Anweisungen für dieSpeicherverwaltung. Das macht er so geschickt, dass sich Codemeist so verhält, wie es ein Programmierer erwarten würde, der miteiner Sprache wie Java aufgewachsen ist.

104 | Kapitel 10: Speicherverwaltung

Page 113: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 113/224

Schauen wir uns ein Beispiel an (bei dem ein alter Objective-C-Hase, der mit der manuellen Referenzzählung vertraut ist, dieHände über dem Kopf zusammenschlagen würde):

id ding1 = [[Ding alloc] initMitName: @"Haus"];id ding2 = [Ding dingMitName: @"Boot"];// Zwei Referenzen, die zwei Objekte referenzierending1 = ding2;// Zwei Referenzen, die ein Objekt referenzierending2= nil;// Eine Referenz, die ein Objekt referenziert

In diesem Beispiel werden zwei Objekte erstellt und Variablenzugewiesen. Beide Objekte werden so lange im Speicher festgehal-ten, wie die von den Variablen gespeicherten Referenzen auf dieObjekte bestehen. Das erste Ding-Objekt wird zur Löschung freige-geben, wenn ding1 ebenfalls die Referenz zugewiesen wird, die vonding2 festgehalten wird, da es nun keine Referenz mehr auf diesesObjekt gibt. Nun gibt es zwei Referenzen auf das zweite   Ding-

Objekt, es wird also noch nicht zur Löschung freigegeben, wenneine der Referenzen, hier die in ding2, gelöscht wird.

So sieht Ihr Code im Idealfall aus, wenn Sie ARC nutzen. Wie Siesehen werden, wenn Sie sich den Abschnitt zur manuellen Refe-renzzählung vornehmen, müssen Sie sich erheblich weniger Gedan-ken über die Speicherverwaltung machen und erheblich wenigerSpeicherverwaltungscode schreiben als bei der manuellen Referenz-

zählung. Das kann allerdings nur der Idealfall sein. Es würdeunausweichlich zu Problemen führen, wenn sich alle Referenzenauf diese Weise verhielten. Zum Beispiel wäre es unmöglich, Refe-renzzyklen zu brechen. ARC unterscheidet deswegen verschiedeneArten von Referenzen, und Sie müssen gegebenenfalls die Art derReferenz signalisieren, die verwendet werden soll.

Starke und schwache ReferenzenUnter ARC werden Variablen, Felder und Eigenschaften in Bezugdarauf unterschieden, wie bindend die von ihnen festgehaltenenReferenzen sind. Referenzen können stark oder schwach sein; starkeReferenzen sind bindend, schwache Referenzen nicht. Nur starkeReferenzen sorgen dafür, dass ein Objekt im Speicher aufbewahrt

ARC (Automatic Reference Counting) | 105

Page 114: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 114/224

wird. Gibt es keine starken Referenzen mehr, wird das Objektfreigegeben und aus dem Speicher entfernt, unabhängig davon, wieviele schwache Referenzen noch darauf bestehen. Alle bestehenden

schwachen Referenzen werden auf  nil gesetzt.Standardmäßig stellen alle Eigenschaften und Variablen, die Siedefinieren, starke Referenzen dar. Das führt zu dem Verhalten, dasder am Anfang dieses Abschnitts vorgestellte Codeauszug aufweist.Wie dort müssen Sie in der Regel so gut wie nichts für die Speicher-verwaltung tun. Sollen sich Felder, Eigenschaften oder Variablenanders verhalten, können Sie das mit den neu eingeführten Eigen-

schaftsattributen und Variablenqualifizierern angeben.

Eigenschaftsattribute

Mit ARC werden zwei neue Eigenschaftsattribute, strong und weak,eingeführt:

strong Der Standardwert, sorgt dafür, dass ein von der Eigenschaftreferenziertes Objekt garantiert erhalten bleibt, solange dieseReferenz besteht bzw. solange diese Referenz auf das entspre-chende Objekt zeigt.

weakGibt an, dass die Referenz eine schwache Referenz ist, die ein

Objekt nicht im Leben hält.

Beispielsweise entspricht also NSString * (strong) name; dem kürze-ren, aber weniger eindeutigen NSString * name;. Beides bewirkt, dassein Objekt, das der Eigenschaft mit

[derda name: [NSString stringWithFormat: @"%@", @"12345678"]];

zugewiesen wird, erhalten bleibt, solange   name  auf dieses Objektzeigt. Das bedeutet, das Objekt wird erst dann freigegeben, wennname ungültig wird oder wenn name z. B. mit

[derda name: nil];

neu zugewiesen wird.

106 | Kapitel 10: Speicherverwaltung

Page 115: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 115/224

Schwache Referenzen benötigen Sie, um Referenzzyklen (Objekt  a

hält eine Referenz auf Objekt  b, das seinerseits eine Referenz auf Objekt a hält) zu durchbrechen. Das ist etwas, das ARC im Unter-

schied zu einer Garbage Collection ohne Hilfe des Programmierersnicht lösen kann. Beispielsweise würden Sie eine schwache Referenznutzen, um bei der Implementierung einer doppelt verketteten Listeeinen Referenzzyklus zu vermeiden:

@interface Listenelement: NSObjectListenelement *(strong) naechstes;Listenelement *(weak) voriges;@end

Ältere Mac OS X- und iOS-Versionen unter-stützen schwache Referenzen nicht. Außerdemgibt es Bibliothekscode, der keine schwachenReferenzen unterstützt. Nutzen Sie in solchenFällen das Eigenschaftsattribut  assign, wennSie eine schwache Referenz benötigen.

Qualifizierer fu r Variablen

Neben den zwei Eigenschaftsattributen gibt es vier Qualifizierer fürVariablen, mit denen Sie Variablen und Felder versehen können,um ihr Bindungsverhalten festzulegen. Die Qualifizierer werden

 jeweils von zwei Unterstrichen eingeleitet:_ _strong 

Der Standardwert. Markiert eine starke Referenz und sorgtdafür, dass das referenzierte Objekt erhalten bleibt, solangediese Referenz besteht.

_ _weak

Markiert eine schwache Referenz, die nur so lange gültig ist, wiees andere, starke Referenzen auf ein Objekt gibt. Wird die letztestarke Referenz auf ein Objekt ungültig, werden alle vorhande-nen schwachen Referenzen auf  nil gesetzt.

ARC (Automatic Reference Counting) | 107

Page 116: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 116/224

_ _unsafe_unretained Markiert ebenfalls schwache Referenzen, die allerdings nichtauf  nil gesetzt werden, wenn das referenzierte Objekt aus dem

Speicher entfernt wird. Wird benötigt, wenn Sie Code schrei-ben, der mit Mac OS X- beziehungsweise iOS-Versionen kom-patibel ist, die keine schwachen Referenzen (__weak) unterstüt-zen, oder um mit Code zu interagieren, der nicht ARC-basiertist.

_ _autoreleasing Markiert Argumente, die per Referenz übergeben und bei der

Rückkehr der Funktion/Methode automatisch freigegeben wer-den.

Wenn Sie das Hintergrundfeld für eine  strong-Eigenschaft explizitangeben müssen, würden Sie folglich den Qualifizierer   __strong

nutzen, bei einer weak-Eigenschaft hingegen den Qualifizierer __weak:

@interface Listenelement: NSObject {

Listenelement * _ _strong _naechstes;Listenelement * _ _weak _voriges;

}Listenelement *(strong) naechstes;Listenelement *(weak) voriges;@end

Auf dem Stack, d. h. methodenlokal, müssen Sie mit  __weak  vor-sichtig sein, zum Beispiel:

id __weak ding = [[Ding alloc] initMitName: @"Hut"];

Da es keine starke Referenz auf das so erstellte Objekt gibt, wird esunmittelbar zur Löschung freigegeben.

Auto-Release-Blo cke

Neben den Eigenschaftsattributen und Variablenqualifizierern wer-den mit ARC die  @autorelasepool-Direktive und die sogenannten

 Auto-Release-Pool-Blöcke eingeführt:

@autoreleasepool {// Code, fur den dieser Auto-Release-Pool-Block aktiv ist

}

108 | Kapitel 10: Speicherverwaltung

Page 117: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 117/224

Cocoa erwartet, dass Ihr Code in einem Auto-Release-Pool-Blockausgeführt wird. Ein Auto-Release-Pool-Block stellt den Auto-Re-lease-Pool bereit, der die Objekte festhält, die automatisch freigege-

ben werden. Gibt es keinen Auto-Release-Pool, führt das zu Spei-cherlöchern. Wenn Sie eine Mac OS X- oder iOS-App schreiben,sorgt das jeweilige Framework, AppKit bzw. UIKit, dafür, dass stetsein Auto-Release-Block verfügbar ist. Deswegen müssen Sie inIhrem Code sehr selten eigene  @autoreleasepool-Blöcke schreiben.Eigene Auto-Release-Pool-Blöcke müssen Sie nur einsetzen,

• wenn Sie eine Konsolenanwendung schreiben,

• wenn Sie einen neuen Thread starten,

• wenn Sie in einer Schleife sehr viele Objekte erstellen.

Neue Regeln

Haben Sie bereits Objective-C-Code geschrieben, der auf einer

manuellen Referenzzählung basiert, müssen Sie beachten, dass sicheinigen Regeln geändert haben:

1. So gut wie alles, was mit der manuellen Speicherverwaltung zutun hat, ist tabu:   retain,   release,   retainCount   und   auto

release  dürfen weder gesendet noch implementiert werden;dealloc  darf nicht mehr gesendet, aber noch implementiertwerden;   dealloc-Implementierungen dürfen nicht   [super

dealloc]  nutzen (das Senden der Nachricht an   super  erfolgtunter ARC automatisch); NSAutoreleasePool-Objekte sind ver-boten (ARC führt stattdessen die  @autoreleasepool-Direktiveund die damit verbundenen Autorelease-Blöcke ein).

2. ARC kümmert sich nur um echte Objective-C-Objekte. Bei derInteraktion mit C bzw. bei der Arbeit mit Core Foundation-Objekten müssen deswegen einige Punkte beachtet werden:C-Structs dürfen keine Objective-C-Objektzeiger enthalten;id-Referenzen und   void *-Zeiger können nicht mehr unpro-blematisch ineinander umgewandelt werden; und Sie müssenspezielle Casts nutzen, die ARC sagen, wie die resultierendenObjekte verwaltet werden.

ARC (Automatic Reference Counting) | 109

Page 118: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 118/224

Page 119: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 119/224

die Runtime beruht auf einem einzigen, eigentlich ziemlich ein-fachen Prinzip:

Sie müssen alle Objekte freigeben, die Sie besitzen, und dürfen

keine Objekte freigeben, die Sie nicht besitzen.

Wenn Sie wissen wollen, ob Sie sich um die Freigabe eines Objektkümmern dürfen und müssen, müssen Sie also wissen, wie Sie inErfahrung bringen, ob Sie ein Objekt besitzen oder nicht. Sie sindBesitzer eines Objekts,

• wenn Sie ein Objekt mit einer Methode erstellen, deren Name

mit alloc, new, copy oder mutableCopy beginnt,• wenn Sie ein Objekt explizit in Besitz nehmen, indem Sie ihm

die retain-Nachricht senden.

Dass eine Methode ein Objekt liefert, das der Aufrufer besitzt, heißt,dass der Referenzzähler für das entsprechende Objekt durch denAufruf der Methode um eins erhöht wird und die Methode dem

Aufrufer die Verantwortung für die korrekte Rücknahme dieserErhöhung überlässt. Welche Methoden ein Objekt liefern, für dasbereits retain aufgerufen wurde, wird allein durch eine Konventiongeregelt. An diese Konventionen müssen Sie sich auch in Ihreneigenen Klassen halten.

Methoden mit Namen, die nicht auf diese Weise beginnen, liefernkonventionsgemäß ein Objekt, das automatisch freigegeben wird.Das heißt, das zurückgelieferte Objekt wird vom aktuellen Auto-Release-Pool am Leben gehalten und dann gelöscht, wenn diesergeleert wird. Erhalten Sie ein Objekt von einer solchen Methoden,müssen Sie davon ausgehen, dass es automatisch freigegeben wird,und müssen selbst dafür sorgen, dass es über die Leerung desaktuellen Auto-Release-Pools erhalten bleibt, wenn Sie es längerbenötigen.

Schauen wir uns das gleiche Beispiel an wie im ARC-Abschnitt:

id ding1 = [[Ding alloc] initMitName: @"Hut"];id ding2 = [Ding dingMitName: @"Elefant"];ding1 = ding2;ding2= nil;

MRC (Manuel Reference Counting) | 111

Page 120: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 120/224

Dieser Code besitzt das Objekt, auf das ding1 zeigt, aber nicht dasObjekt, auf das  ding2  zeigt, da das erste Objekt mit  alloc  erstelltwurde, das zweite hingegen nicht. Der Name der Methode, die zur

Erstellung des zweiten Objekts genutzt wird, sagt konventions-gemäß, dass das zurückgelieferte Objekt automatisch freigegebenwird. Der Code ist also für die Freigabe des ersten Objekts verant-wortlich, während er das zweite Objekt nicht freigeben darf.

In dieser Form führt dieser Code deswegen zu einem Speicherloch.Wenn ding1 auf  ding2 gesetzt wird, wird die letzte Referenz auf dasDing-Objekt gelöscht. Der Code hat keine Möglichkeit mehr, das

Objekt freizugeben. Dem  retain, das das  [Ding alloc]  impliziert,kann nie mehr das erforderliche release folgen.

Bei einer manuellen Speicherverwaltung müsste der Code dafürsorgen, dass das Ding-Objekt korrekt freigegeben wird.

Das lässt sich auf zweierlei Weise erreichen:

1. Das Objekt freigeben, bevor die Referenz überschrieben wirdid ding1 = [[Ding alloc] initMitName: @"Hut"];id ding2 = [Ding dingMitName: @"Elefant"];[ding1 release];ding1 = ding2;ding2 = nil;

2. Das Objekt automatisch freigeben

id ding1 = [[[Ding alloc] initMitName: @"Hut"] autorelea-se];id ding2 = [Ding dingMitName: @"Elefant"];ding1 = ding2;ding2 = nil;

Im ersten Fall wird das Objekt freigegeben, unmittelbar bevor dieReferenz darauf überschrieben wird. Im zweiten Fall wird es an den

aktuellen Auto-Release-Pool übergeben. Das endgültige   releasewird ihm erst gesendet, wenn der Auto-Release-Pool gelöscht wird.

112 | Kapitel 10: Speicherverwaltung

Page 121: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 121/224

Es wird ziemlich heiß debattiert, welches Ver-fahren besser ist. release sagt (auch dem LeserIhres Codes) eindeutig, dass Sie das Objekt

nicht mehr benötigen, und erlaubt der Run-time, den Speicher unmittelbar freizugeben. autorelease   sagt nur, dass Sie es irgendwannnicht mehr benötigen werden und es der Run-time überlassen, wann es endgültig freigegebenwird. Auf Codeebene sind beide Verfahren inder Regel trotzdem gleichwertig.  autoreleasewird nur kritisch, wenn Sie sehr viele Objekte(z. B. in einer Schleife) nutzen. Dann sollten Sieentweder   release   nutzen oder einen lokalenAuto-Release-Pool einsetzen, der so häufig ge-leert wird, dass der Speicherbedarf nicht über-hand nimmt.

Beachten Sie, dass für diesen Code in Bezug auf das zweite  Ding-

Objekt nichts unternommen werden muss. Der Methodennamesagt, dass das erstellte Objekt automatisch freigegeben wird. Ganzgleich, wie viele Referenzen es darauf gibt – es wird irgendwann vonder Runtime freigegeben. Anders sieht es aus, wenn Sie das  Ding-Objekt länger festhalten, z. B. einem Feld zuweisen wollen:

self->ding = [Ding dingMitName: @"Elefant"];

Da das auf die   dingMitName:   -Nachricht erstellte Objekt auto-matisch freigegeben wird, wird es irgendwann von der Runtimefreigegeben. Das Objekt, auf das  self->ding zeigt, kann also jeder-zeit verschwinden. Sein Fortbestehen muss gesichert werden, indemdem Objekt die retain-Nachricht gesendet wird:

self->ding = [[Ding dingMitName: @"Elefant"] retain];

Diesem   retain  muss natürlich später ein korrespondierendes   release folgen. Dazu definieren Sie in Ihren Klassen  -dealloc-Nach-richten, in denen Sie die Ivars und Eigenschaften Ihrer Objektefreigeben. Für das von uns in Besitz genommene Feld sähe das soaus:

- (void) dealloc {[self->ding release];

MRC (Manuel Reference Counting) | 113

Page 122: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 122/224

[super dealloc];}

Nachdem alle eigenen Felder freigegeben wurden, leitet   -dealloc

die Nachricht an die Oberklasse weiter, damit diese hinter sichaufräumen kann.

Auto-Release-Pools

Auto-Release-Pool-Blöcke funktionieren unter MRC genau so wieunter ARC. Sie nutzen die   @autoreleasepool-Direktive, um einen

Auto-Release-Pool anzufordern.Vor der Einführung von ARC und den Auto-Release-Pool-Blöckenmit   @autoreleasepool   basierten Auto-Release-Pools auf   NSAuto

releasePool-Objekten, die angelegt werden mussten, weil Cocoaerwartet, dass ein Auto-Release-Pool verfügbar ist. In älterem Codewerden Sie deswegen auf folgende Konstruktion stoßen:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];...[pool drain];

NSAutoreleasePool-Objekte sind spezielle Objekte, deren Verhaltensich von anderen Objekten unterscheidet. Sie legen den Pool einmalan, nutzen ihn hinterher aber nie direkt. Die Runtime sorgt dafür,dass die Objekte, denen Sie die autorelease-Nachricht senden, dem

Pool hinzugefügt werden. Außerdem können sie z. B. nicht mitretain festgehalten werden.

114 | Kapitel 10: Speicherverwaltung

Page 123: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 123/224

KAPITEL 11

Laufzeitinformationen

Laufzeitinformationen zu Objekten und Klassen können Sie übereinige Nachrichten erhalten, die vom   NSObject-Protokoll und derKlasse NSObject definiert werden. Für weitergehende Informationenmüssen Sie eventuell direkt auf die in   objc/runtime.h  definiertenFunktionen zurückgreifen. Das Foundation-Framework bietet zu-sätzlich einige Funktionen, die die Interaktion mit der Laufzeit

vereinfachen.

Die Objective-C-LaufzeitumgebungDie Objective-C-Runtime definiert die Umgebung, in dem Ihr Ob- jective-C-Code läuft. Sie definiert die C-Funktionen, in deren Auf-rufe Ihre Objective-C-Konstrukte übersetzt werden. Teile der Infor-mationen, die die Laufzeitumgebung über die Elemente Ihres

Objective-C-Codes zur Verfügung stellt, werden auch auf Objective-C-Ebene, d. h. über Klassen- und Objektnachrichten, zugänglichgemacht. Aber für manche Informationen und Operationen gibt esauf Objektebene kein Gegenstück. Wenn Sie diese nutzen wollen,müssen Sie sich mit der Laufzeitumgebung und ihren Funktionenvertraut machen. Das kann diese Einführung in Objective-C nichtleisten.

Die Funktionen der Laufzeitumgebung ermöglichen Ihnen unteranderem folgende Operationen:

• Zugriff auf Klasseninformationen wie Name, Oberklasse, über-nommene Protokolle, Methoden- und Ivar-Listen.

• Zugriff auf Informationen zu den Instanzvariablen und Me-thoden von Objekten bzw. Klassen.

| 115

Page 124: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 124/224

• Interaktion mit den Instanzvariablen von Objekten.

• Zugriff auf Informationen zu Protokollen.

• Zugriff auf Informationen zu Selektoren und dynamische Re-

gistrierung von Selektoren.• Dynamische Hinzufügung von Klassen zur Laufzeitumgebung.

• Dynamische Hinzufügung von Methoden zu Klassen.

• Dynamische Ersetzung von Methodenimplementierungen.

• usw.

Weitere Informationen finden Sie in Apples   Objective-C Runtime-

Reference   und im   objc/runtime.h-Header, in dem diese Featuresdeklariert werden.

ObjektinformationenDie Nachrichten   -hash  und   -description   liefern eine numerische

bzw. eine textuelle Repräsention eines Objekts.   -hash   entsprichtden Hashcode-Eigenschaften bzw. Methoden, die Sie aus anderenProgrammiersprachen wie Java kennen, und liefert einen Wert, derein Objekt zureichend eindeutig identifiziert.  -description  ist mitden   toString()- bzw.   ToString-Methoden von Java und C# ver-gleichbar. Sie wird z. B. vom %@-Formatparameter genutzt, um eineTextdarstellung eines Objekts zu erhalten (falls es keine Implemen-

tierung für die spezifischere   -descriptionWithLocale:-Nachrichtbietet, die viele Foundation-Klassen implementieren). Das bedeutet,die zwei Logging-Anweisungen unten liefern die gleiche Ausgabe:

id datum = [NSDate date];NSLog(@"Datum: %@", datum);NSLog(@"Datum: %@", [datum description]);

Die NSObject-Implementierung von -hash liefert die Speicheradressedes Objekts, die Implementierung von -description einen Wert derForm   <NSObject: 0x123456789>, wobei der Hexwert die Speicher-adresse darstellt. Die meisten Framework-Klassen überschreiben die-description-Nachricht und lassen sie Werte liefern, die eine an-gemessenere Repräsentation ihrer Instanzen darstellen.

116 | Kapitel 11: Laufzeitinformationen

Page 125: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 125/224

-isEqual:  prüft wie erwartet, ob der Empfänger einem anderenObjekt gleich ist. Die   NSObject-Implementierung vergleicht, wieüblich, Speicheradressen und betrachtet nur Zeiger auf dasselbe

Objekt als gleich. Wenn Sie für die Objekte Ihrer Klassen einanderes Vergleichsverhalten wünschen, können Sie -isEqual: über-schreiben. Beachten Sie, dass Sie dann auch   -hash  überschreibenmüssen.

Klasseninformationen

Die Nachrichten -class und  -superclass liefern die Class-Objekte,die die Klasse des Objekts bzw. seine Oberklasse repräsentieren. Mitden Nachrichten   -isMemberOfClass:   und   -isKindOfClass:   kanngeprüft werden, ob ein Objekt eine Instanz einer Klasse oder eineInstanz einer Klasse ist, die von einer anderen Klasse abgeleitet ist.Die Klassennachrichten   +class,   +superclass   und   +isSubclassOf

Class: bieten äquivalente Informationen.

Beachten Sie, dass der direkte Zugriff auf dasisa-Feld seit Objective-C 2.0 veraltet ist undin diesem Buch deswegen nicht dokumentiertwird. Seit der Einführung von Tagged Pointern(markierten Zeigern, die unmittelbar einenWert enthalten und nicht auf eine Adresse

zeigen) kann er außerdem zu Programmfeh-lern führen.

Klassenobjekte

Klassen beschreiben die Struktur von Objekten, d. h. ihre Instanz-variablen und Methoden. Aber Klassen sind selbst auch Objekte.

Der Typ Class ist zwar ein Objective-C-Typ, der über einen Zeigerauf einen opaken C-Struct-Typ deklariert wird, er wird zur Laufzeitaber durch ein Objekt repräsentiert. Anders als Klasseninstanzen,die gewöhnlichen Objekte, mit denen Sie arbeiten, werden dieseKlassenobjekte von der Laufzeit erstellt, wenn die Klasse geladenwird.

Klasseninformationen | 117

Page 126: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 126/224

Die Klasse eines Objekts kann mit der Instanznachricht   -class

abgerufen werden:

Class stringKlasse = [@"123" class];

Das Klassenobjekt kann ebenfalls über die Klassennachricht +class

erhalten werden:

Class stringKlasse = [NSString class];

Der Klassenname selbst kann für das Klassenobjekt nur als Emp-fänger einer Nachricht einstehen. Wenn Sie ein Klassenobjektbenötigen, müssen Sie es sich über eine dieser Nachrichten oder

die weiter unten aufgeführten Alternativen beschaffen.

Dass Klassen Objekte sind, macht es überhaupt erst möglich, ihnenNachrichten zu senden. Wenn Sie eine Klassennachricht senden,wird diese mit dem Klassenobjekt als Empfänger ausgeführt. AlsObjekt sind sie gleichzeitig aber auch Teil der   NSObject-Klassen-hierarchie und können als   NSObject-Instanzen behandelt werden.

Das heißt, Sie können Klassenobjekten  NSObject-Instanznachrich-ten wie respondsToSelector: senden:

id klasse = [@"123" class];if ([klasse respondsToSelector: @selector(stringWithFormat:)) {

…}

Wenn Sie Klassenobjekte festhalten, ist es deswegen in der Regel

empfehlenswert, diese über eine Objektreferenz statt über einenClass-Zeiger festzuhalten.

Klassen können diese   NSObject-Instanzmethode durch Klassen-methoden gleichen Namens überschreiben. Beispielsweise definiertNSObject selbst eine +class-Nachricht, die bei einem Aufruf auf demKlassenobjekt die -class-Instanznachricht verdeckt.

Da Klassen Objekte sind, können sie in den Cocoa-Collection-Klas-sen gespeichert werden, z. B. in einem Array:

id klassen = @[[NSString class], [NSNumber class], [NSArrayclass]];

118 | Kapitel 11: Laufzeitinformationen

Page 127: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 127/224

Sie können sogar als Dictionary-Schlüssel verwendet werden, daNSObject speziell zu diesem Zweck die NSCopying-analogen Klassen-methoden +copyWithZone: und  +mutableCopyWithZone: bietet.

Metaklassen

Da Klassen Objekte sind, haben sie selbst auch eine Klasse. Diese»Klassenklasse« wird als  Metaklasse  bezeichnet. Metaklassen wer-den genutzt, um die Nachrichten aufzulösen, die dem Klassenobjektgesendet werden.

Auf Objektebene haben Sie keine Möglichkeit, an das Metaklassen-objekt für eine Klasse zu gelangen. Wenn Sie auf einem Klassen-objekt class aufrufen, wird nicht die Klasse der Klasse, sondern nurdie Klasse selbst zurückgeliefert. Das liegt daran, dass die Klassen-nachricht   class   einfach   self   zurückliefert, das in einer Klassen-methode das Klassenobjekt repräsentiert.   [[Klasse   class] class]

liefert also dasselbe Klassenobjekt wie [Klasse class].

Metaklasseninformationen können Sie deswegen nur mit Funktio-nen der Objective-C-Laufzeitumgebung abrufen, die für Klassen-objekte eine andere Semantik als die +class-Klassenmethode bieten.Die Laufzeitfunktion   object_getClass()   liefert das Metaklassen-objekt für eine Klasse, wenn das übergebene Objekt ein Klassen-objekt ist. Metaklassen haben die folgenden drei Eigenschaften:

1. Die Metaklasse hat den gleichen Namen wie die Klasse selbst,zum Beispiel:

id klasse = [NSString class];id metaklasse = object_getClass(klasse);NSLog(@"Klasse: %@, Metaklasse: %@", klasse, metaklasse);NSLog(@"Gleiche Klasse? %@", klasse == metaklasse ? @"Ja" :@"Nein");

Die Ausgabe ohne Zeitstempel hat die folgende Gestalt. DieAusgabe für die letzte Codezeile zeigt Ihnen, dass die beidenKlassen trotz gleichen Namens unterschiedliche Objekte imSpeicher darstellen, das Klassen- und das Metaklassenobjekt:

Klasse: NSString, Metaklasse: NSStringGleiche Klasse? Nein

Klasseninformationen | 119

Page 128: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 128/224

Page 129: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 129/224

eine Klasse zu diesem Namen finden kann. Die Laufzeitumgebungbietet die Funktionen objc_getClass() und objc_lookUpClass(), diedie Klasse zu einem übergebenen C-String suchen. Alle Funktionen

liefern nil, wenn in der Laufzeitumgebung keine Klasse mit einementsprechenden Namen registriert ist.

Beachten Sie, dass Operationen, die auf Klassennamen basieren,inhärent fragil sind. Eines der speziellen Probleme, denen dieseVerfahren bei der Objective-C-Programmierung auf den Cocoa-Plattformen unterliegen, wird im folgenden Abschnitt illustriert.

Klassenabha ngige Verhalten

Wenn das Verhalten Ihres Codes von der Klasse der Objekteabhängt, mit denen er operiert, sollten Sie beachten, dass dietatsächliche Klasse eines Objekts nicht notwendigerweise der Klasseentspricht, die zu seiner Erstellung genutzt wurde! Schauen Sie sichz. B. folgenden Code an:

id mArray = [NSMutableArray new];Class mArrayClass = [NSMutableArray class];NSLog(@"Instanzklasse: %@", [mArray class]);NSLog(@"Instanzoberklasse: %@", [mArray superclass]);NSLog(@"Klassen: %@", [NSMutableArray class]);NSLog(@"Oberklasse: %@", [NSMutableArray superclass]);NSLog(@"Ist das Objekt eine Instanz dieser Klasse? %@",

[mArray isMemberOfClass:mArrayClass] ? @"JA" : @"NEIN");

NSLog(@"Ist das Objekt ein Objekt dieser Art? %@",[mArray isKindOfClass:mArrayClass] ? @"JA" : @"NEIN");

Die Ausgabe (ohne Zeitstempel) dürfte eine etwas andere Gestalthaben, als Sie vielleicht erwarten:

Instanzklasse: __NSArrayMInstanzoberklasse: NSMutableArrayKlasse: NSMutableArray

Oberklasse: NSArrayIst das Objekt eine Instanz dieser Klasse: NEINIst das Objekt ein Objekt dieser Art: JA

Die NSMutableArray-Instanz, mit der Sie arbeiten, ist tatsächlich alsoeine Instanz einer Unterklasse von  NSMutableArray. In diesem Fallkönnten Sie das NSMutableArray-Objekt also nur mit der -isKindOf

Class:-Nachricht als eine   NSMutableArray-Instanz erkennen.

Klasseninformationen | 121

Page 130: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 130/224

Page 131: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 131/224

object_getClass([@1 class]), // Metaklasse// Meta-Metaklasseobject_getClass(object_getClass([@1 class]))];

for (id objekt in klassen) {

BOOL istKlasse = class_isMetaClass(object_getClass(objekt));NSLog(@"%@ ist Klasse? %@ ", objekt,istKlasse ? @"Ja" : @"Nein");

if(istKlasse) {NSLog(@"Und Metaklasse? %@ ",

class_isMetaClass(objekt) ? @"Ja" : @"Nein");}

}

FunktionsinformationenMit den Nachrichten   -respondsToSelector:   und   + instancesRes

pondToSelector:   kann geprüft werden, ob der Empfänger einenSelektor unterstützt. Senden Sie  -respondsToSelector:  einem Ob-

 jekt, um in Erfahrung zu bringen, ob es die angegebene Instanz-

nachricht unterstützt. Senden Sie -respondsToSelector: der Klasse,um in Erfahrung zu bringen, ob sie die angegebene Klassennach-richt unterstützt. Die Klassennachricht   +instancesRespondTo

Selector: prüft, ob die Instanzen einer Klasse eine Instanznachrichtunterstützen.

Klassen reagieren nicht auf Instanznachrichten, Instanzen reagierennicht auf Klassennachrichten. Folgende Ausdrücke demonstrierendas am Beispiel der  NSString-Nachrichten  +stringWithFormat  und-substringToIndex. Alle Ausdrücke werden zu YES ausgewertet:

[NSString respondsToSelector:@selector(stringWithFormat:)] == YES;

[NSString respondsToSelector:@selector(substringToIndex:)] == NO

[NSString instancesRespondToSelector:

@selector(substringToIndex:)] == YES[@"123" respondsToSelector:@selector(stringWithFormat:)] == NO;

[@"123" respondsToSelector:@selector(substringToIndex:)] == YES;

Beispiele für den praktischen Einsatz dieser Methoden finden Sie inKapitel 12, Messaging .

Funktionsinformationen | 123

Page 132: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 132/224

Diese Methoden prüfen auch, ob der Klasse Methodenimplemen-tierungen dynamisch mit   +resolveInstanceMethod   oder   +resolve

ClassMethod  hinzugefügt werden. Wenn die Klasse den Weiterlei-

tungsmechanismus nutzt,   -forwardingTargetForSelector:   bzw.-forwardInvocation, kann es hingegen sein, dass diese Methode NO

liefert, obwohl ein Objekt die Nachricht dank Weiterleitung unter-stützt. Gegebenenfalls sollten Sie   -respondsToSelector:   entspre-chend überschreiben.

 Jede Anwendung muss selbst entscheiden, ob der Umstand, dasseine Klasse einen Selektor nicht unterstützt, als Fehler betrachtet

werden soll oder nicht.

Weitere Informationen zu den Nachrichten, die ein Objekt versteht,bzw. einen Zeiger auf die Implementierung selbst können Sie sichüber die Nachrichten  -methodSignatureForSelector:  und   -method

ForSelector:   beschaffen, die im   Kapitel 12,   Messaging , ausführ-licher betrachtet werden. Noch tiefer können Sie mit den Laufzeit-

funktionen der   method_-Gruppe bohren, die ein  Method-Argumenterwarten, das Sie sich mit den Funktionen   class_getInstance-

Method()  und   class_getClassMethod()  beschaffen können, die je-weils eine Klasse und einen Selektor als Argument erwarten.

Protokollinformationen

Das NSObject-Protokoll deklariert eine -conformsToProtocol:-Nach-richt, mit der Sie prüfen können, ob der Empfänger das angegebeneProtokoll unterstützt. Die Klasse   NSObject  deklariert eine ergän-zende  +conformsToProtocol:-Nachricht. Diese beiden Nachrichtenweisen unterschiedliches Verhalten auf.

Die Klassennachricht prüft nur, ob die Schnittstelle explizit oderimplizit die Übereinstimmung mit einem Protokoll deklariert. Im-plizit wird die Übereinstimmung mit einem Protokoll deklariertwenn eine der Oberklassen die Übereinstimmung mit dem Pro-tokoll deklariert, oder wenn ein Protokoll, das von der Klasse odereiner ihrer Oberklassen übernommen wird, das Protokoll ein-schließt. Da   NSMutableSet  von   NSSet   abgeleitet ist und   NSSet  das

124 | Kapitel 11: Laufzeitinformationen

Page 133: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 133/224

Protokoll   NSSecuringCoding   übernimmt, das seinerseits   NSCoding

einschließt, gilt z. B. Folgendes:

[NSMutableSet conformsToProtocol: @protocol(NSCoding)] == YES

Die Instanznachricht hingegen prüft tatsächlich, ob der Empfängerdie im Protokoll deklarierten Nachrichten unterstützt. Sie kanndeswegen als effizientere Alternative für  -respondsToSelector:  ge-nutzt werden, wenn die Unterstützung mehrerer Nachrichten über-prüft werden muss.

Der folgende Code deklariert eine Klassenmethode, die  -conforms

ToProtocol:  nutzt, um eine Liste mit Kopien der Elemente eineranderen Liste zu erstellen, die das Protokoll NSCopying unterstützen.In diesem Fall wäre es mit einer Überprüfung der Unterstützung der-copy-Nachricht nicht getan, da  -copy in  NSObject zwar deklariert,aber nicht funktionsfähig implementiert wird:

+(void) trenneListe:(id<NSFastEnumeration>)listeinKopien:(NSMutableArray **)kopie

originale:(NSMutableArray **)geborgt {for (id element in liste) {

if ([element conformsToProtocol: @protocol(NSCopying)]) {[*kopie addObject: [element copy]];

} else {[*geborgt addObject: element];

}}

}

Da zwei Listen zurückgegeben werden, nutzt der Code Referenz-parameter. Die Parametervariablen müssen deswegen mit dem De-referenzierungsoperator dereferenziert werden, wenn den referen-zierten Objekten eine Nachricht gesendet werden soll. Beachten Sie,dass der Code allozierte und initialisierte  NSMutableArray-Objekteerwartet.

Protokollinformationen | 125

Page 134: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 134/224

Page 135: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 135/224

KAPITEL 12

Messaging

Der Objective-C-Nachrichtenmechanismus ist von Grund auf dyna-misch. Nachrichten werden erst zur Laufzeit an eine Methoden-implementierung gebunden.

Bei der Kompilierung werden die Nachrichtennamen durch  Selek-toren ersetzt. Empfänger, Selektor und Argumente werden genutzt,um die Nachricht in einen Aufruf der Runtime-Funktion

objc_msgSend()   umzuwandeln.   objc_msgSend()   sucht dann zurLaufzeit den Code, der die  Methodenimplementierung   stellt, ruftdiesen auf und übergibt ihm die Argumente. Zusätzlich erhält derCode den Empfänger und den Selektor (in Form von   self   und_cmd). Dieser Vorgang nimmt notwendigerweise mehr Zeit in An-spruch, als sie ein direkter Funktionsaufruf benötigen würde. Daskann man an für die Leistung kritischen Punkten umgehen, indem

man eine Methodenimplementierung abruft und direkt aufruft(siehe Abschnitt »Implementierungen cachen« auf Seite 135).

Kann keine passende Methodenimplementierung gefunden werden,kann die Klasse dynamisch eine Methodenimplementierung stellenoder die Nachricht an ein anderes Objekt weiterleiten. Für die dyna-mische Methodenimplementierung   können Sie die   NSObject-Metho-

den -resolveInstanceMethod bzw. -resolveClassMethod implementie-ren, für die   Nachrichtenweiterleitung    die   NSObject-Methoden-forwardingTargetForSelector:   und/oder   -forwardInvocation:

(siehe   Kapitel 12,   Messaging , Abschnitt   »Dynamische Methoden-implementierung« auf Seite 137   bzw.  »Nachrichtenweiterleitung«auf Seite 139).

| 127

Page 136: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 136/224

Springt keiner dieser Mechanismen ein, wird dem Objekt die-doesNotRecognizeSelector-Nachricht gesendet, deren   NSObject-Standardimplementierung eine Ausnahme auslöst und damit nor-

malerweise die Programmausführung abbricht.

KompilierungDie eigentliche Methodenimplementierung wird zwar erst zur Lauf-zeit ermittelt, aber der Compiler muss trotzdem bereits bei derKompilierung entscheiden, welchen Rückgabetyp und welche Ar-

gumenttypen der  objc_msgSend()-Aufruf verwendet. Dazu prüft erdie Selektoren anhand der Deklarationen, die in der Kompilations-einheit gültig sind.

Unter ARC und MRC sind Nachrichten nur unter folgenden Bedin-gungen uneingeschränkt zulässig:

• Wenn die Nachricht vom deklarierten statischen Typ des

Objektzeigers, über den sie gesendet wird, deklariert bzw.geerbt wird.

• Wenn die Signatur für eine Nachricht, die über einen Objekt-zeiger des Typs id gesendet wird, ermittelt werden kann.

Was passiert, wenn ein Selektor unbekannt ist, hängt davon ab,welche Speicherverwaltungstechnologie zum Einsatz kommt.

Unter ARC werden unter folgenden Bedingungen folgende Fehlergemeldet:

• Es führt zu einem »Keine sichtbaren Schnittstellen für …deklarieren den Selektor …«-Fehler, wenn einem Objekt eineNachricht gesendet wird, die für den entsprechenden Objekt-typ nicht deklariert ist, wenn der Objektzeiger statisch mit

einem konkreten Typ typisiert ist.• Es führt zu einem »Kein Selektor für Methode … be-

kannt«-Fehler, wenn einem Objekt, das über einen Objekt-zeiger mit dem Typ   id   festgehalten wird, eine Nachrichtgesendet wird, die nicht bekannt ist.

128 | Kapitel 12: Messaging

Page 137: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 137/224

Unter MRC ist der Compiler nachsichtiger. Nachrichten führen niezu Fehlern. Die folgenden Konstellationen führen zu Warnungen:

• Es führt zu einer »…-Methode nicht gefunden«-Warnung,

wenn eine Nachricht nicht bekannt ist, unabhängig davon, obdas Objekt über einen  id-Zeiger oder einen Zeiger mit einemkonkreten statischen Typ festgehalten wird.

• Es führt zu einer »Es kann sein, dass … nicht auf …-Nachrichtreagiert«-Warnung, wenn einem Objekt über eine statisch miteinem konkreten Typ typisierte Referenz eine Nachricht ge-sendet wird, die bekannt, aber für den entsprechenden Objekt-typ nicht deklariert ist.

Ein Beispiel: Angenommen, Sie haben eine Klasse Aufgabe, die eine-aufMorgenVerschieben-Methode deklariert:

// Aufgabe.h#import <Foundation/Foundation.h>@interface Aufgabe : NSObject

-(void) aufMorgenVerschieben;@end;

Es reicht dann, diesen Header in eine Kompilationseinheit zuimportieren, damit der Compiler unter ARC keinen Fehler mehrmeldet, wenn Sie einem beliebigen von einer id-Referenz festgehal-tenen Objekt eine -aufMorgenVerschieben-Nachricht senden:

import "Aufgabe.h"…id text = @"Dringend";[text aufMorgenVerschieben]; // Kein Fehler, keine Warnung…

Selektoren

Ein Selektor ist ein eindeutiger Bezeichner, der eine Methode iden-tifiziert. Es gibt nur einen Selektor für alle Methoden gleichenNamens, auch wenn mehrere Klassen eine Methode eines bestimm-ten Namens deklarieren. Das heißt, wenn Sie zwei Klassen  Vogel

und  Flugzeug  haben, die beide eigene  -fliegen-Methoden bieten,wird diese Methode durch denselben Selektor identifiziert.

Selektoren | 129

Page 138: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 138/224

Das kann bei der Kompilierung zu Problemen führen, wenn in einerKompilationseinheit mehrere Methoden bekannt sind, die dengleichen Namen, aber unterschiedliche Argument- bzw. Rück-

gabetypen haben. Das kann zur Folge haben, dass der Compilerfalsche Aufrufe kodiert. Unter ARC erhalten Sie in diesem Fall eineWarnung. Dieses Problem können Sie lösen, indem Sie den Emp-fänger auf den gewünschten Typ casten, zum Beispiel:

[(Flugzeug *)ju fliegen];

Objective-C definiert einen eigenen Typ, SEL, für Selektoren. Selek-toren können mit der Compilerdirektive   @selector()   oder derRuntime-Funktion NSSelectorFromString() abgerufen werden. DasArgument für @selector() ist ein Token, das einen gültigen Metho-dennamen repräsentieren muss, das Argument für   NSSelector

FromString() ein  NSString-Objekt, das einen Methodennamen an-gibt. So könnten Sie sie einsetzen, um die Selektoren für zweiNSString-Methoden abzurufen:

SEL stringAnfang = @selector(substringToIndex:);SEL stringEnde = NSSelectorFromString(@"substringFromIndex:");

Bei der Direktive muss der Methodenname bei der Kompilierungfeststehen, bei der Funktion kann er zur Laufzeit aufgebaut werden.

ImplementierungenZur Laufzeit dienen Selektoren als dynamische   Funktionszeiger ,über die die für das jeweilige Objekt passende Methodenimplemen-tierung  ermittelt wird. Die Methodenimplementierung ist der Code,der tatsächlich zur Ausführung kommt, wenn einem Empfängereine Nachricht gesendet wird. Implementierungen werden durchden Objective-C-Typ IMP beschrieben, der folgendermaßen definiertist:

typedef id (*IMP)(id, SEL, ...)

Diese Typdefinition definiert einen Zeiger auf eine C-Funktion, dieein id- und ein SEL-Argument sowie eine beliebige Anzahl weitererArgumente erwartet und einen Wert des Typs id zurückliefert.

130 | Kapitel 12: Messaging

Page 139: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 139/224

Die ersten beiden Argumente beschreiben self, die aktuelle Instanz,und _cmd, die aktuell verarbeitete Nachricht. Diese beiden Argumentesind das, was eine C-Funktion zu einer Objective-C-Methode macht.

Wenn Sie eine C-Funktion schreiben, die als Methodenimplementie-rung einstehen soll, muss sie also mindestens diese beiden Argu-mente deklarieren. Arbeiten Sie direkt mit den Laufzeitfunktionenzur Interaktion mit Methodenimplementierungen, müssen Sie in derRegel die entsprechenden Werte für diese Argumente angeben.

Der in der Typdeklaration angegebene Rückgabetyp  id ist nur einPlatzhalter für den tatsächlichen Rückgabetyp der Methode.

Wenn Sie direkt mit Implementierungen arbeiten, sollten Sie nie»rohe«   IMPs aufrufen. Stattdessen sollten Sie einen   IMP   immer auf einen Funktionszeigertyp casten, dessen Rückgabetyp und dessenweitere Argumenttypen dem Rückgabetyp und den Argumenttypender jeweiligen Nachricht entsprechen. Beispiele für die direkte Arbeitmit IMPs finden Sie in mehreren der nachfolgenden Abschnitte (unter

anderem in »Implementierungen cachen« auf Seite 135).

Selektoren dynamisch ausfu hrenÜblicherweise steht die Nachricht, die einem Objekt gesendet wird,bereits bei der Kompilierung fest. Selektoren können eingesetztwerden, um die Nachricht, die einem Objekt gesendet wird, erst

zur Laufzeit festzulegen. Dazu können Sie entweder die Methodender -performSelector:-Familie, ein NSInvocation-Objekt oder einendirekten Aufruf von objc_msgSend() nutzen.

-performSelector:

Das NSObject-Protokoll definiert drei -performSelector:-Methoden,

-performSelector:,   -performSelector:withObject,   -performSelector:withObject:withObject, die von   NSObject   implementiert wer-den. Außerdem bietet   NSObject   einige zusätzliche   -performSe

lector-Methoden, mit denen Selektoren verzögert oder auf spezifischen Threads ausgeführt werden können. Alle   -performSe

lector-Methoden erwarten einen Selektor und liefern einen Wert

Selektoren dynamisch ausführen | 131

Page 140: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 140/224

des Typs id. Die verschiedenen Varianten akzeptieren zwischen nullund zwei id-Argumenten.

Der nachfolgende Code nutzt   -performSelector:withObject:, um

aus einem   NSDictionary-Objekt dynamisch mit der   -objectForKey:-Nachricht ein Element abzurufen:

id dict = @{@"a" : @1, @"b" : @2};SEL sel = @selector(objectForKey:);NSLog(@"%@", [dict performSelector: sel withObject: @"b"]);

Beim gleichen Dict entspricht das:

[dict objectForKey: @"b"];

Wenn Sie   -performSelector:   wie hier miteinem   SEL-Argument nutzen, das nichtkonstant ist, erhalten Sie unter ARC eine War-nung, die besagt, dass der -performSelector:zu einem Speicherloch führen kann, weil der

Selektor unbekannt ist.

Wenn Sie auf Basis von Selektoren Methoden ausführen wollen, dieObjective-C-Typen erwarten oder liefern, müssen Sie   objc_

msgSend() oder ein NSInvocation-Objekt nutzen.

NSInvocation

Die Klasse   NSInvocation   ermöglicht es, Objekte zu erstellen, dieNachrichten beschreiben. Diese kapseln Empfänger und Argumen-te, schließen Informationen zum Rückgabetyp und zu den Argu-menttypen ein und bieten Möglichkeiten, die Nachricht auszufüh-ren und den Rückgabewert abzurufen.

Beachten Sie, dass der  NSInvocation-Mecha-nismus erheblich langsamer als   -performSelector:   ist. Das macht ihn für zeitkritischeAnwendungsteile ungeeignet. Weichen Sie ge-gebenenfalls auf   objc_msgSend   oder Imple-mentierungscaching aus.

132 | Kapitel 12: Messaging

Page 141: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 141/224

Sie sollten ein NSInvocation-Objekt immer über die Klassennachricht+invocationWithMethodSignature:   erstellen, die eine Methoden-signatur in Form eines  NSMethodSignature-Objekts erwartet. Dieses

beschaffen Sie sich für einen Selektor über eine der  NSObject-Metho-den  +instanceMethodSignatureForSelector:   oder   -methodSignature

ForSelector:. Ein NSInvocation-Objekt, das den objectForKey:-Auf-ruf beschreibt, den wir oben mit -performSelector:withObject: aus-geführt haben, können Sie sich also folgendermaßen beschaffen:

id dict = @{@"a" : @1, @"b" : @2};id key = @"b";

SEL sel = @selector(objectForKey:);id sig = [NSDictionary instanceMethodSignatureForSelector: sel];id aufruf = [NSInvocation invocationWithMethodSignature: sig];

Bevor das   NSInvocation-Objekt ausgeführt werden kann, müssenZiel, Selektor und Argumente gesetzt werden:

[aufruf setSelector: sel];[aufruf setTarget: dict];

[aufruf setArgument: &key atIndex: 2];

Das erste Argument für -setArgument:atIndex: hat den Typ void *,mit dem unter C ein Zeiger beschrieben wird, der auf alles zeigenkann. Sie geben die Argumente unabhängig vom Typ – bei einemObjekt wie bei einem int oder einem NSRect – also mit dem Adress-operator & über einen Zeiger an.

Das zweite Argument für  -setArgument:atIndex: ist ein  NSInteger,der die Position des Arguments im zu generierenden objc_msgSend()

Aufruf angibt. Argumente 0 und 1 dieser Funktion sind Ziel undSelektor, die stets über die dedizierten Nachrichten  -setSelector:

und  -setTarget:  (bzw. beim Aufruf über  -invokeWithTarget:) ge-setzt werden sollten. Das erste Argument der eigentlichen Nachrichtist also das dritte Argument des   objc_msgSend()-Aufrufs und hat

deswegen den Index 2. Jetzt können Sie das NSInvocation-Objekt folgendermaßen ausführen:

[aufruf invoke];id wert;[aufruf getReturnValue: &wert];

Selektoren dynamisch ausführen | 133

Page 142: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 142/224

Das Argument von  -getReturnValue: hat ebenfalls den Typ  void *

und soll auf den Buffer zeigen, in den der Rückgabewert geschrie-ben werden soll. Wenn Sie als Rückgabewert ein Objekt erwarten,

übergeben Sie einfach die Adresse einer Variablen eines kompati-blen Objekttyps. Hat der Rückgabewert einen Objective-C-Typ,müssen Sie etwas mehr Arbeit leisten. Ein Beispiel sehen Sie imfolgenden Code, der ein   NSInvocation-Objekt nutzt, um einemNSArray-Objekt die length-Nachricht zu senden:

SEL sel = @selector(length);id sig = [NSString instanceMethodSignatureForSelector: sel];

id aufruf = [NSInvocation invocationWithMethodSignature: sig];[aufruf setSelector: sel];[aufruf invokeWithTarget: text];void *buffer = (void *)malloc([sig methodReturnLength]);[aufruf getReturnValue: buffer];NSUInteger laenge = *(NSUInteger *)(buffer);

Nachdem aufruf mit -invokeWithTarget ausgeführt wurde, wird einBuffer für das Ergebnis eingerichtet. Der Speicherplatz dafür muss

manuell mit der C-Funktion  malloc()  alloziert werden. Die benö-tigte Menge Speicherplatz kann mit der   NSMessageSignature-Me-thode   -methodReturnLength   ermittelt werden. In der letzten Zeilewird der Buffer zunächst auf den richtigen Zeigertyp gecastet(NSUInteger *)   und dann mit dem Dereferenzierungsoperator   *

dereferenziert, um den Wert zu erhalten.

objc_msgSend()

objc_msgSend()  ist eine (oder besser die) Funktion der Objective-C-Laufzeitumgebung. Sie ist dafür verantwortlich, dass bei jederNachricht, die Sie senden, die richtige Methode auf dem richtigenObjekt zur Ausführung kommt. Dafür sucht sie zunächst die fürdiese Kombination von Klasse und Selektor passende Implementie-

rung, führt diese dann mit dem Objekt und den eventuell überge-benen Argumenten aus und liefert schließlich den Rückgabewertdes Aufrufs als den eigenen Rückgabewert zurück.

Der  objc_msgSend()-Aufruf wird vom Compiler generiert. Norma-lerweise sollten Sie diese Funktion nie selbst aufrufen müssen. Aber...

134 | Kapitel 12: Messaging

Page 143: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 143/224

objc_msgSend() ist folgendermaßen deklariert:

id objc_msgSend(id self, SEL sel, …)

Wenn der Compiler einen objc_msgSend() erstellt, kodiert er diesen jedoch mit den erforderlichen Typen für den jeweiligen Aufruf.Wollen Sie  objc_msgSend() einsetzen, sollten Sie den Aufruf eben-falls auf den entsprechenden Funktionszeigertypen casten. ZumBeispiel könnten Sie einem Stringobjekt folgendermaßen dyna-misch die length-Nachricht senden:

NSInteger res;

SEL sel = @selector(length);res = ((NSInteger)(*)(id, SEL)objc_msgSend)(@"123", sel);

In der letzte Zeile wird der Funktionszeiger  objc_msgSend  auf denTyp  (NSInteger)(*)(id, SEL)  gecastet. Das ist eine Funktion, dieeinen NSInteger-Wert liefert und einen id- sowie einen SEL-Wert alsArgumente erwartet. Eine entzerrte Version dieser Zeile sähe so aus:

typedef NSInteger (*IntVoidFunc)(id, SEL);

IntVoidFunc str_len = (IntVoidFunc)objc_msgSend;NSInteger res = str_len(@"123", @selector(length));

Die erste Zeile deklariert den Funktionszeigertyp  IntVoidFunc, diezweite definiert eine Funktion namens   str_len   mit diesem Typ,indem objc_msgSend auf diesen Typ gecastet wird, und die dritte ruftdie so definierte Funktion auf.

Implementierungen cachenEs ist möglich, die dynamische Methodenauflösung zu umgehen,z. B. weil eine Nachricht, in einer Schleife vielleicht, so oft gesendetwerden muss, dass die bei jedem Aufruf erfolgende dynamischeMethodenauflösung zu Leistungseinbußen führt.

NSObject   definiert zwei Nachrichten,   -methodForSelector:   und+instanceMethodForSelector:, über die ein Zeiger auf die Imple-mentierung einer Instanz- oder Klassenmethode ermittelt werdenkann. Die Instanzmethode -methodForSelector: kann einer Instanzgesendet werden, um Zugriff auf die Implementierung einer In-stanzmethode zu erhalten, oder der Klasse selbst, um Zugriff auf eine Klassenmethode zu erhalten. Über die Klassennachricht

Implementierungen cachen | 135

Page 144: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 144/224

+instanceMethodForSelector:  kann die Implementierung einer In-stanzmethode über die Klasse abgerufen werden.

Folgendermaßen könnte man eine Implementierung cachen, um

eine Operation auf allen Elementen einer Liste durchzuführen:id text = @"";id texte = @[@"eins", @"zwei", @"drei"];NSInteger ergebnis = 0;SEL laengeSel = @selector(length);typedef NSInteger (*IntVoidFunc)(id, SEL);IntVoidFunc laenge_imp =

(IntVoidFunc)[text methodForSelector: laengeSel];for (text in texte) {

ergebnis += laenge_imp(text, laengeSel);}

Dieser Code nutzt die gleiche Typdefinition für den Funktionszeiger-typ   IntVoidFunc   wie das letzte Beispiel des vorangegangenen Ab-schnitts. Hier wird dieser Typ aber nicht genutzt, um einenobjc_msgSend()-Aufruf auf den Typ der Methodenimplementierungzu casten, sondern um eine Funktionszeigervariable zu definieren, diedie mit  methodForSelector:   abgerufene Methodenimplementierungfesthält. Diese wird dann in der Schleife jeweils mit dem aktuellenIterationswert als Argument für den Parameter self aufgerufen.

Der wesentliche Unterschied ist, dass der objc_msgSend()-Aufruf dieMethodenimplementierung jeweils dynamisch auflöst. Wird die

Methodenimplementierung z. B. wie hier mit  methodForSelector:abgerufen und gespeichert, kann sie direkt aufgerufen werden. Diedynamische Methodenauflösung und die mit ihr verbundenen Kos-ten werden umgegangen.

Beachten Sie, dass Sie zu dieser Maßnahme nurgreifen sollten, wenn leistungskritische Teile ei-

ner Anwendung dadurch tatsächlich beschleu-nigt werden können. Die dynamische Metho-denauflösung von Objective-C ist äußerstschnell und effizient und greift intern bereitsauf Caching-Mechanismen zurück. Der Beispiel-code oben ist selbst bei einer Liste von 10 Mil-lionen Elementen nicht konsistent schneller alseine ganz gewöhnliche Objektnachricht!

136 | Kapitel 12: Messaging

Page 145: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 145/224

Dynamische MethodenimplementierungWenn für einen Empfänger keine Implementierung einer Nachrichtgefunden werden kann, erhält er die Möglichkeit, dynamisch eineImplementierung zu stellen. Dazu ruft die Laufzeitumgebung dieKlassenmethoden   +resolveInstanceMethod:   bzw.   +resolveClass

Method: auf, je nachdem, ob es sich bei der unbeantworteten Nach-richt um eine Instanznachricht oder eine Klassennachricht handelt.

Eine   +resolveInstanceMethod:- bzw.   +resolveClassMethod:-Imple-mentierung kann die Laufzeitfunktion   class_addMethod()  nutzen,

um der Klasse dynamisch eine Implementierung für einen Selektorhinzuzufügen.   class_addMethod()  erwartet die Klasse, der die Im-plementierung hinzugefügt werden soll, den Selektor für die Imple-mentierung, die Implementierung selbst und einen C-String, der dieSignatur mit Typcodes beschreibt. Die Signatur der Funktion hatfolgende Gestalt:

BOOL class_addMethod(Class cls, SEL name,IMP imp, const char *types)

Basis für die Implementierung bildet üblicherweise eine C-Funk-tion. Diese muss als erstes und zweites Argument wie üblich einenid- und einen SEL-Wert erwarten, die self und _cmd annehmen. Erstdarauf folgen die eigentlichen Parameter der Objective-C-Nach-richt.

Nehmen wir beispielsweise an, Sie haben eine Klasse, die einNSArray-Objekt kapselt, und wollen gegebenenfalls dynamisch-objectAtIndex:   unterstützen, falls Objekte Ihrer Klasse für einNSArray   einstehen müssen. Eine C-Funktion, die diese Operationstellt, könnte so aussehen:

id dynamicObjectAtIndex(id self, SEL _cmd, NSUInteger idx) {if ([[self liste] count] > idx) {

return [[self liste] objectAtIndex: idx];} else {

return nil;}

}

Der dritte Funktionsparameter entspricht dem eigentlichen Para-meter, der in einer  objectAtIndex:-Nachricht übergeben wird. Die

Dynamische Methodenimplementierung | 137

Page 146: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 146/224

+resolveInstanceMethod:-Implementierung könnte dann folgendeGestalt haben:

+ (BOOL)resolveInstanceMethod:(SEL)sel {

if (sel == @selector(objectAtIndex:)) {class_addMethod([self class], sel,(IMP)dynamicObjectAtIndex, "@@:Q");

return YES;} else {

return [super resolveInstanceMethod:sel];}

}

Als Klasse übergeben wir die Klasse von self, als Implementierungdie auf einen   IMP  gecastete C-Funktion. Das letzte Argument be-schreibt die Typsignatur der Funktion. Jedes Zeichen im String gibteinen Typ an, das erste den Rückgabetyp, die weiteren die Argu-menttypen. @ gibt einen Objektwert an, : einen Selektor und Q einenunsigned long long-Wert (der Typ, dem   NSUInteger   auf einem64-Bit-System entspricht). Beachten Sie, dass wir uns nun auf 

C-Ebene bewegen und dass für die Angabe der Typsignatur einC-String verwendet wird.

Statt einer C-Funktion kann die Basis für die Implementierung auchein Blockobjekt sein. Dazu wird ein definierter Block mit der Lauf-zeitfunktion imp_implematationWithBlock() in einen IMP  umgewan-delt.   imp_implementationWithBlock()   nimmt das Blockargument,kopiert den Block auf den Heap und liefert ein Sprungbrett (deroffizielle Terminus ist   Trampolin), über das der Block wie eineMethodenimplementierung aufgerufen werden kann. Da Blocks(siehe Kapitel 2, Syntax, Abschnitt »Blocks« auf Seite 18) C-Funk-tionen mit nur einem vorgeschalteten Argument (self) entsprechen,sieht die »Blocksignatur« etwas anders aus – der   SEL-Parameterentfällt. Nachfolgende Blockdefinition ist der Definition der Funk-tion dynamicObjectAtIndex() weiter oben äquivalent:

id (^blockOAI)(id, NSUInteger) =^id(id self, NSUInteger idx) {

if ([[self liste] count] > idx) {return [[self liste] objectAtIndex: idx];} else { return nil;

}};

138 | Kapitel 12: Messaging

Page 147: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 147/224

Page 148: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 148/224

Der Code prüft mit  -respondsToSelector:, ob das Objekt  anderes

Objekt die erhaltene Nachricht unterstützt. Wenn das der Fall ist,wird  anderesObjekt  als Rückgabewert des Aufrufs zurückgegeben.

Unterstützt das Objekt die Nachricht nicht, wird die Elternklassen-version der Nachricht aufgerufen und ihr Rückgabewert geliefert.Die Standardimplementierung in   NSObject   liefert   nil. Liefert-forwardingTargetForSelector: einen Objektwert ungleich nil, ver-sucht die Laufzeit, diesem Objekt die Nachricht zu senden, andern-falls wird auf dem ursprüngliche Empfänger   -forwardInvocation

aufgerufen.

Beachten Sie, dass die Nachrichtenverarbeitung nach der Umleitungnicht mehr im Kontext Ihres eigenen Objekts erfolgt, sondernvollkommen vom neuen Objekt übernommen wird. Eventuelle-forwardInvocation:- oder   -doesNotRespondToSelector:-Über-schreibungen auf Ihrer eigenen Klasse kommen also nicht mehr zurAusführung

-forwardInvocation:

Der Empfänger erhält die   -forwardInvocation:-Nachricht, wennihm ein unbekannter Selektor gesendet wurde, der von keiner deranderen Maßnahmen des Nachrichtenmechanismus verarbeitetwurde. Das Argument der Nachricht ist ein  NSInvocation-Objekt,das die unbekannte Nachricht beschreibt. (NSInvocation   wird in

Abschnitt   »NSInvocation« auf Seite 132   genauer beschrieben.)Dieses wird in einer -forwardInvocation:-Überschreibung üblicher-weise genutzt, um einen geeigneten Empfänger für die Nachricht zusuchen und das  NSInvocation-Objekt dann mit diesem Empfängerals Ziel auszuführen.

Die Laufzeitumgebung sorgt dafür, dass das Ergebnis der Ausfüh-

rung des   NSInvocation-Objekts (das über die Eigenschaft   returnValue   zugänglich ist) zum Rückgabewert der unbekannten Nach-richt wird. Da   returnValue   den Typ   void *   hat, werden Rück-gabewerte beliebigen Typs unterstützt.

Wenn Sie  -forwardInvocation:  überschreiben, müssen Sie zusätz-lich die Nachricht   -methodSignatureForSelector:   überschreiben.Die Methodensignatur, die über diese Nachricht abgerufen wird,

140 | Kapitel 12: Messaging

Page 149: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 149/224

wird zur Konstruktion des   NSInvocation-Objekts benötigt. Kannkeine Methodensignatur für einen Selektor ermittelt werden,kommt es zu einem Laufzeitfehler. Folgende Überschreibung der

beiden Nachrichten bewirkt das Gleiche wie die   -forwardingTargetForSelector:-Überschreibung aus dem letzten Abschnitt (istallerdings erheblich langsamer):

- (NSMethodSignature*)methodSignatureForSelector:(SEL)sel {id sig = [super methodSignatureForSelector: selector];if (!sig) {

sig = [@"abc" methodSignatureForSelector: selector];}

return sig;}-(void)forwardInvocation:(NSInvocation *)anInvocation {

if ([anderesObjekt respondsToSelector:[anInvocation selector]]) {

[anInvocation invokeWithTarget: anderesObjekt];} else {

[super forwardInvocation: anInvocation];

}}

-methodSignatureForSelector:  liefert ein Objekt, das eine Metho-densignatur beschreibt, oder nil. Die Methodensignatur ist entwe-der eine Signatur für eine eigene oder eine geerbte Methode (die hierermittelt wird, indem die Nachricht an die Oberklassen delegiertwird) oder eine Signatur für eine Methode der Klasse von  anderes

Objekt. Besitzt keine der Klassen eine Methode, die dem Selektorentspricht, wird das nil-Ergebnis der Aufrufe durchgereicht.

-invokeWithTarget: ruft das  NSInvocation-Objekt mit einem ande-ren Objekt als Empfänger für die gekapselte Nachricht auf. Falls daspotenzielle Zielobjekt die unbekannte Nachricht nicht unterstützt,wird die Oberklassenversion von  -forwardInvocation:  aufgerufen.Die   NSObject-Implementierung ruft   -doesNotRespondToSelector:,dessen NSObject-Implementierung einen Laufzeitfehler auslöst.

Sie müssen das  NSInvocation-Objekt nicht mit  -invoke bzw.  -invoke

WithTarget: ausführen, um den Rückgabewert zu generieren, sondernkönnen ihn auch manuell setzen. Nehmen Sie z. B. an, die ObjekteIhrer Klasse sollen auf eine verirrte integerValue-Nachricht die Längedes Strings liefern, den sie kapseln. Diesen Rückgabewert könnten Sie

Nachrichtenweiterleitung | 141

Page 150: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 150/224

mit -setReturnValue: folgendermaßen setzen, ohne das NSInvocation-Objekt auszuführen (vorausgesetzt,   -methodSignatureForSelector:

liefert ein passendes NSMethodSignature-Objekt für diesen Selektor):

- (void)forwardInvocation:(NSInvocation *)anInvocation {if ([anInvocation selector] == @selector(integerValue)) {

NSInteger intVal = [[self test] length];[anInvocation setReturnValue: &intVal];

} else {[super forwardInvocation:anInvocation];

}}

-setReturnValue erwartet wie die Methoden zum Setzen der Argu-mente einen Zeiger auf die Daten.

142 | Kapitel 12: Messaging

Page 151: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 151/224

KAPITEL 13

Key/ Value-Coding

Als Key/Value-Coding (kurz KVC) bezeichnet man den indirekten,dynamischen Zugriff auf die Instanzvariablen eines Objekts. DieObjective-C-Key/Value-Coding-Infrastruktur besteht aus einem inNSKeyValueCoding.h als  NSObject-Kategorie deklarierten informel-len Protokoll, NSKeyValueCoding, und einem Satz von Konventionenfür die Benennung der Zugriffsmethoden von Eigenschaften.

NSKeyValueCoding definiert Methoden, mit denen Sie über  Schlüsseloder Schlüsselpfade mit Objektdaten interagieren können. Schlüsselbzw. Schlüsselpfade sind Strings, für die Schlüssel/Wert-Beziehungenbestehen, die 1:1- oder 1:m-Verhältnisse modellieren können. 1:1heißt, das auf eine Schlüsselanfrage ein Wert geliefert wird. 1:mbedeutet, dass zu einem Schlüssel mehrere Werte geliefert werden,üblicherweise in Form eines Sammlungsobjekts (z. B. eines NSArray).

KVC-Konformita tDie  NSObject-Standardimplementierung der KVC-Methoden bildenStringschlüssel auf die Namen der Zugriffmethoden und Instanz-variablen eines Objekts ab. Eine Klasse ist KVC-konform für einenSchlüssel schluessel, wenn eine der folgenden Bedingungen zutrifft:

•   Das Objekt hat eine Eigenschaft namens schluessel bzw. einenschluessel-Getter und einen   setSchluessel:-Setter (wenn dieentsprechenden Daten auch verändert werden können sollen).

• Das Objekt hat eine Instanzvariable names   schluessel  bzw._schluessel.

| 143

Page 152: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 152/224

•   Wenn der Schlüssel in einem 1:m-Verhältnis zu den Datensteht, muss die Eigenschaft/Instanzvariable einen Typ haben,der die Art der Sammlung modelliert (z. B.  NSArray oder NSSet).

Betrachten wir das am Beispiel der folgenden Klasse:@interface RPGFigur {@private

NSString * _name;}@property NSArray *waffen;@property NSArray *ruestung;@property int leben;- (id) initMitName: (NSString *) name;- (NSString *) name;@end

Auf die Eigenschaft leben kann über den Schlüssel @"leben" zugegrif-fen werden, auf das gekapselte private Feld  _name über @"name" undauf die Listen waffen und  ruestung über @"waffen bzw. @"ruestung".@"leben"  und   @"name"   stellen 1:1-Beziehungen dar,   @"waffen"  und@"ruestung" 1:m-Beziehungen.

Beachten Sie, dass KVC die Kapselung des Felds _name umgehen kann.Wenn es keine set…-Methode gibt, greift KVC standardmäßig direktauf das Hintergrundfeld zu und ignoriert dabei Sichtbarkeitsangaben.Dieses Verhalten können Sie ändern, indem Sie die NSKeyValueCoding-Klassenmethode  accessInstanceVariablesDirectly überschreiben und

NO liefern lassen, um einen Schreibversuch fehlschlagen zu lassen.

Schlu sselbasierte Interaktion mitObjektenNSKeyValueCoding deklariert verschiedene Methoden zur schlüssel-

basierten Interaktion mit Objekten. Die elementarste dieser Metho-den ist -valueForKey:. Sie liefert den Wert zu einem Schlüssel, unab-hängig davon ob, dieser ein 1:1- oder ein 1:m-Verhältnis begründet.Die Methode erwartet einen  NSString, der den Schlüssel angibt, undliefert ein eventuelles Ergebnis über eine id-Referenz, zum Beispiel:

id name = [spieler valueForKey: @"name"];

144 | Kapitel 13: Key/ Value-Coding

Page 153: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 153/224

Haben die Daten, die mit dem Schlüssel assoziiert sind, einenskalaren Typ, werden sie in einen passenden   NSValue-Wrapperverpackt. Vor der Weiterverarbeitung ist also gegebenenfalls ein

geeigneter Cast erforderlich:int verlust = MAX_LEBEN - (int)[spieler valueForKey: @"leben"];

1:m-Verhältnisse können z. B. über eine Beziehung auf ein NSArray

umgesetzt sein:

id waffe3 = [ [spieler valusForKey:@"waffen"] objectAtIndex: 2];

Das Gegenstück zu  -valueForKey: ist  -setValue:forKey: und setztden Wert für einen Schlüssel:

[spieler setValue: @MAX_LEBEN forKey: @"leben"];

Schlägt das Abfragen oder Setzen über einen Schlüssel fehl, wird dasProgramm standardmäßig mit einer   NSUndefinedKeyException  ab-gebrochen. Dieses Verhalten können Sie ändern, indem Sie die

Methoden   -valueForUndefinedKey:   (für die Abfrage) und-setValue:forUndefinedKey: (für das Setzen) überschreiben.

Schlu sselpfadeSchlüsselpfade sind zusammengesetzte Schlüssel, über die unmittel-bar auf tiefere Schichten des Objektgraphen zugegriffen werden

kann. NSKeyValueCoding definiert eigene Methoden für die schlüssel-pfadbasierte Objektinteraktion – genauer: Zu vielen   …forKey-Me-thoden gibt es korrespondierende …forKeyPath-Methoden.

In einem Schlüsselpfad werden die einzelnen Pfadelemente mit demPunktoperator voneinander abgegrenzt. Beispielsweise könnte manmit dem Schlüsselpfad @"name.length unmittelbar auf die Länge des

in _name gespeicherten Werts zugreifen, z. B. um ihn für die Anzeigeauf die passende Länge zu bringen:

if ([spieler valueForKeyPath: @"name.length"] > 8) {return [NSString stringWithFormat: @"%@%@",

[s.name substringWithRange:NSMakeRange(0, 8)], @"…"];}

Schlüsselpfade | 145

Page 154: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 154/224

Schlüsselpfade unterstützen außerdem von einem   @   eingeleiteteSchlüsselpfadoperatoren. Es gibt Mengenoperationen wie   @count

oder   @avg  und einige Operatoren für Operationen auf Objekten,

Listen oder Mengen. Zum Beispiel liefert   @"waffen.@count"   dieAnzahl an Waffen,  @"[email protected]" eine Liste mitden Namen der Waffen (wenn Waffen   Waffe-Objekte mit einername-Eigenschaft sind) und  @"[email protected]" die durch-schnittliche Länge der Waffennamen.

Gibt es kein linkes Pfadelement, bezieht sich die Operation auf dasObjekt selbst, z. B. sind die beiden folgenden Ausdrücke äquivalent:

[spieler.waffen valueForKeyPath: @"@count"][spieler valueForKeyPath: @"waffen.@count"]

Wenn die Objekte, die in der Liste oder Menge enthalten sind, dieOperatoraktion nicht unterstützen, wird eine Ausnahme ausgelöst.Beispielsweise können Sie keinen Durchschnitt für ein Array mitNSString-Elementen berechnen lassen

Virtuelle Schlu ssel1:m-Verhältnisse müssen nicht notwendigerweise tatsächlichen Ei-genschaften oder Instanzvariablen entsprechen, sondern könnenemuliert werden. Dazu müssen Unterstützungsmethoden imple-mentiert werden, die die Operationen der entsprechenden Samm-

lungsklasse ermöglichen – bei einer Liste (NSArray), die nur lesbarist, z. B.   countOfSchluessel   sowie   -objectInSchluesselAtIndex:

und/oder   -schluesselAtIndexes:. Man könnte den Schlüssel@"inventar"   beispielsweise folgendermaßen ein (nur lesbares)1:m-Verhältnis modellieren lassen, das die Inhalte der Listen waffen

und ruestung zusammenfasst:

- (NSUInteger)countOfInventar {return [[self waffen] count] + [[self ruestung] count];}- (id) objectInInventarAtIndex: (NSUInteger) index {

if (index < [[self waffen] count]) {return [[self waffen] objectAtIndex: index];

} else {return [[self ruestung] objectAtIndex:

(index - [[self waffen] count])];

146 | Kapitel 13: Key/ Value-Coding

Page 155: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 155/224

}}

countOf…   liefert die Anzahl an Elementen in der Liste, hier die

Summe der Elemente der beiden Listen, die wir zum Inventarzusammenfassen.   objectIn…AtIndex   ist dafür verantwortlich, dasObjekt an der angegebenen Position der zusammengesetzten Listezu liefern. Rufen Sie diese Liste über den Schlüssel   inventar  ab,erhalten Sie ein Proxyobjekt, das alle Aktionen unterstützt, die Sieauf einem gewöhnlichen NSArray vornehmen können:

id inventar = [spieler valueForKey: @"inventar"];

NSUInteger index = // Irgendwo einen Index beschaffenid gegenstand;if (index < [inventar count]) {

gegenstand = [inventar objectAt: index];}

Soll die Liste, die hinter dem 1:m-Verhältnis steht, schreibbar sein,müssen weitere Methoden ergänzt werden (zumindest   -insert

Object:inSchluesselAtIndex:   und/oder   -insertSchluessel:atIndexes:   sowie   -removeObjectFromSchluesselAtIndex:   und/oder-removeSchluesselAtIndexes:). Für die Implementierung andererSammlungsarten benötigen Sie andere Methoden. Mehr Informa-tionen finden Sie in Apples »Key-Value Coding ProgrammingGuide«.

KVC-ValidierungDie KVC-Infrastruktur vereinheitlicht die Validierung neuer Werte,und die KVC-Konformität fordert eigentlich, dass die Validierungvon Setter-Parametern nicht im Setter erfolgen, sondern in eigenen-validateSchluessel:error:-Nachrichten implementiert werdensoll. Diese Methoden müssen als Parameter den neuen Wert in

Form der Adresse einer id-Referenz sowie die Adresse einer NSError-Referenz akzeptieren. Sie liefern einen BOOL-Wert, der anzeigt, ob derneue Wert ein gültiger Wert für den entsprechenden Schlüssel ist.Stellt er keinen gültigen Wert dar, wird zusätzlich der  error-Parame-ter auf ein NSError-Objekt gesetzt. Eine Validierungsmethode für den@"leben"-Schlüssel auf der Klasse  Spieler  könnte folgende Gestalthaben:

KVC-Validierung | 147

Page 156: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 156/224

- (BOOL)validateLeben:(id *)objecterror:(NSError **)error {

if ([*object isKindOfClass: [NSNumber class]] &&[*object compare: @0] > NSOrderedAscending &&

[*object compare: @MAX_LEBEN]]< NSOrderedDescending) {return YES;

} else {*error = [NSError errorWithDomain: FEHLER_DOMAIN

code: FEHLER_CODEuserInfo: @{

NSLocalizedDescriptionKey: @"Falscher Wert"}];

return NO;}

}

Die Methode prüft, ob der Wert ein  NSNumber-Objekt ist und ob ereine Zahl im gültigen Bereich repräsentiert (größer als 0 und kleinerals der irgendwo definierte Maximalwert). Ist das der Fall, liefert sieYES, andernfalls setzt sie ein NSError-Objekt und liefert NO.

Die Validierungsmethoden können direkt aufgerufen werden oderüber die NSKeyValueCoding-Methoden – validateValue:forKey:error:

bzw. – validateValue:forKeyPath:error:.

Schlu sselpfadoperatoren

Tabelle 13-1 bietet eine Aufstellung der in Schlüsselpfaden unter-stützten Operatoren:

Tabelle 13-1: Schlüsselpfadoperatoren

Operator Beschreibung

@avg   Durchschnitt der Elementwerte.

@count   Anzahl Elemente.

@max   Großtes Element.@min   Kleinstes Element.

@sum   Summe der Elemente.

@unionOfObjects   Vereinigungsmenge der durch den Pfad an-gegebenen Elemente des Objektgraphen.

@distinctUnionOfObjects   Wie @unionOfObjects, die Vereinigungs-menge enthalt aber keine Duplikate.

148 | Kapitel 13: Key/ Value-Coding

Page 157: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 157/224

Tabelle 13-1: Schlüsselpfadoperatoren (Fortsetzung)

Operator Beschreibung

@unionOfArrays   Vereinigungsmenge der Elemente der Quell-

arrays.@distinctUnionOfArrays   Wie @unionOfArrays, aber die Vereini-

gungsmenge enthalt keine Duplikate.

@unionOfSets   Vereinigungsmenge der Elemente der Quell-mengen.

@distinctUnionOfSets   Wie @unionOfSets, aber die Vereinigungs-menge enthalt keine Duplikate.

Schlüsselpfadoperatoren | 149

Page 158: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 158/224

Page 159: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 159/224

KAPITEL 14

Objektarchivierung

Als Archivierung wird der Vorgang bezeichnet, mit dem das kom-plexe Geflecht eines Objektgraphen so gesichert wird, dass er zueiner anderen Zeit und/oder an einem anderen Ort exakt wieder-hergestellt werden kann. »Exakt wiederhergestellt« heißt dabei,dass die Identität der einzelnen Objekte und ihre Beziehungenuntereinander bei der Dearchivierung bewahrt bleiben.

Objective-C deklariert mit dem in   NSObject.h   deklarierten Pro-tokoll NSCoding eine einheitliche Archivierungsinfrastruktur, die Sieeinsetzen können, wenn Sie Objektdaten speichern müssen, sichaber keine Gedanken über ein Speicherungsformat machen wollen.Objective-C-Archive können Objektive-C-Objekte, skalare C-Ty-pen und Structs festhalten. Typen, deren Implementierung platt-formabhängig ist, können nicht gespeichert werden.

Klassen, die die Archivierung unterstützen wollen, müssen diesesProtokoll übernehmen. Viele Klassen der Cocoa-APIs unterstützendie Archivierung, unter anderem auch die wichtigen »Collec-tion«-Klassen.

Cocoa unterscheidet die Archivierung in ein

transparentes Format, aus dem ein Objektgraphexakt rekonstruiert werden kann, von der Seria-lisierung, bei der ein Objektgraph in ein wohl-definiertes externes Format wie JSON oder Pro-perty-Listen überführt wird. Eine Serialisierungkann in der Regel nur mit einfacheren Objekt-sammlungen, Listen oder Dicts beispielsweise,umgehen, und der Graph wird bei der Deseria-

| 151

Page 160: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 160/224

lisierung nicht exakt wiederhergestellt. Ent-hielte eine Liste drei Mal dasselbe Objekt, wür-den bei der Deserialisierung z. B. drei verschie-dene Kopien des Objekts angelegt. Da dieSerialisierung keine   NSObject-Einrichtung ist,sondern von API-Klassen wie   NSJSONSerialization oder  NSPropertyListSerialization ge-stellt wird, werden wir uns mit dieser Technikhier nicht befassen.

NSCoding deklariert zwei Methoden: -encodeWithCoder: schreibt die

Daten für ein Objekt in ein Archiv, und -initWithCoder: initialisiertein Objekt aus den Daten in einem Archiv, dearchiviert also dieDaten. Wenn Ihre Klasse die Archivierungsinfrastruktur unterstüt-zen will, muss sie die Konformität zu NSCoding deklarieren und diesebeiden Methoden implementieren. Sie kommen zum Einsatz, wennein Objekt archiviert oder aus einem Archiv wiederhergestellt wer-den soll.

- (void)encodeWithCoder:(NSCoder *)encoder

Kodiert den Empfänger mit dem angegebenen Coder-Objekt.

- (id)initWithCoder:(NSCoder *)decoder

Liefert ein Objekt, das aus dem als Argument angegebenenCoder-Objekt initialisiert wird.

Beide Methoden erwarten ein Coder-Objekt, über das die Methodemit dem für sie transparenten Hintergrundspeicher interagiert. EinCoder-Objekt ist eine Instanz einer Unterklasse der abstraktenFoundation-Klasse   NSCoder, die die Schnittstelle für die Archivie-rung und Wiederherstellung der verschiedenen Datenelemente de-finiert, aus denen ein Objekt bestehen kann.

Sie können eigene Coder definieren oder einen der von Cocoagestellten Coder nutzen, die beide aus zwei Klassen bestehen – einerArchivierer-Klasse und einer Dearchivierer-Klasse, die jeweils eineSeite der NSCoder-Schnittstelle implementieren. Der Coder definiert,welche Gestalt die Archivierung hat.

Die beiden zentralen Objective-C-Coder sind die Archivierer-Dear-chivierer-Kombinationen   NSArchiver/NSUnarachiver   und   NSKeyed

152 |

Page 161: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 161/224

Archiver/NSKeyedUnarchiver. Die erste definiert sequenzielle Ar-chive, die zweite schlüsselbasierte Archive.

Sequenzielle und schlu sselbasierteArchiveBei einem sequenziellen Archiv werden die Daten nacheinander indas Archiv geschrieben und müssen bei der Wiederherstellunggenau in dieser Reihenfolge aus dem Archiv gelesen werden. Dasheißt auch, dass die in einem sequenziellen Archiv enthaltenenDaten immer vollständig gelesen werden müssen (oder zumindestbis zu dem Punkt, an dem die Daten stehen, die im aktuellenKontext relevant sind). Bei einem schlüsselbasierten Archiv hin-gegen werden die Daten mit einem Schlüssel versehen, über den siebei der Wiederherstellung in beliebiger Reihenfolge und in beliebi-gem Umfang gelesen werden können.

In der Regel werden Sie schlüsselbasierte Archive nutzen. Sequen-zielle Archive sind beim Zugriff weniger flexibel und werden unteriOS außerdem nicht unterstützt.

Die NSCoding-Methoden implementierenWenn sich ein Objekt archivieren soll, nutzt es das übergebene

Coder-Objekt, um die Werte seiner Eigenschaften zu sichern, damitdiese aus dem Archiv wiederhergestellt werden können. Schauenwir uns das am Beispiel der Tier-Klasse mit den Stringeigenschaftenname und  art sowie der int-Eigenschaft alter an, die wir in diesemBuch gelegentlich schon zu Beispielzwecken eingesetzt haben:

@interface Tier : NSObject <NSCoding>@property NSString * name;@property NSString * art;@property int alter;@end

Die NSCoding-Methoden implementieren | 153

Page 162: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 162/224

Page 163: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 163/224

Wenn Sie komplexere Objective-C-Typen, z. B. Structs, archivierenmüssen, ist es in der Regel empfehlenswert, die Elemente separat zuarchivieren, da nur so sichergestellt werden kann, dass alle Ele-

mente korrekt archiviert werden.

Sequenzielle Archivierung

Beachten Sie, dass der Code oben davon ausging, dass als CoderNSKeyedArchiver- und   NSKeyedUnarchiver-Objekte übergeben wer-den. Ein Aufruf einer der Methoden mit einem NSArchiver- respek-

tive   NSUnarchiver-Objekt würde zu einer Ausnahme führen, weilvon diesen Klassen die   …forKey-Varianten der   NSCoder-Methodennicht unterstützt werden.

Eine reine   NSArchiver/NSUnarchiver-basierte   NSCoding-Unterstüt-zung hätte folgende Gestalt:

- (void)encodeWithCoder:(NSCoder *)encoder {[encoder encodeObject: [self name]];

[encoder encodeObject: [self art]];[encoder encodeValueOfObjCType: @encode(int)

at: &self->_alter];}- (id)initWithCoder:(NSCoder *)decoder {

self.name = [decoder decodeObject];self.art = [decoder decodeObject];[self decodeValueOfObjCType: @encode(int) at: &self->_alter];

}

In neuem Code sollten Sie grundsätzlichschlüsselbasierte Archive nutzen. Aber eskann passieren, dass Sie gelegentlich noch auf sequenzielle Archive stoßen, da sie nicht offi-ziell veraltet sind.

Den Coder pru fen

Wenn Sie nicht wissen, wie der Code Ihrer Klasse genutzt werdenwird, können Sie die NSCoder-Methode -allowsKeyedCoding verwen-den, um den Archivierungsprozess anzupassen:

Die NSCoding-Methoden implementieren | 155

Page 164: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 164/224

if ([coder allowsKeyedCoding]) {// Schlusselbasierter Code

} else {// Sequenzieller Code

}

Coder-ObjekteZur Archivierung/Dearchivierung selbst nutzen Sie ein entsprechen-des Coder-Objekt, das mit einem Ziel bzw. einer Quelle für dieObjektdaten verbunden ist. Die Coder-Klassen bieten dazu die

Klassennachrichten   +archivedDataWithRootObject:   und   +archiveRootObject:toFile:   bzw.   +unarchiveObjectWithData:   und   +unar

chiveObjectWithFile:, mit denen auf die Schnelle ein Objektgraphdirekt in einer Datei oder einem  NSData-Objekt gespeichert werdenkann. Wenn Sie mehrere Objekte oder Objektgraphen in einemArchiv speichern wollen, können Sie mit der Instanznachricht-initForWritingWithMutableData: ein Objekt erstellen, über das Sie

in ein   NSMutableData-Objekt als Datenspeicher schreiben. Mit-initForReadingWithData:   erstellen Sie ein Objekt, über das SieObjektgraphen aus einem NSData-Speicher lesen können.

Unabhängig davon, für welche der Optionen Sie sich entscheiden,sorgt der Coder dafür, dass auf den Objekten des Graphen dieArchivierungs- bzw. Dearchivierungsmethode aufgerufen wird.

Zunächst die NSKeyedArchiver-Methoden:

+ (NSData *)archivedDataWithRootObject:(id)rootObject

Erstellt ein Archiv für den Objektgraphen, dessen Wurzelobjektals Parameter übergeben wird, und liefert es in Form einesNSData-Objekts.

+ (BOOL)archiveRootObject:(id)rootObject

toFile:(NSString *)pathErstellt ein Archiv für den Objektgraphen, dessen Wurzelobjektals Parameter übergeben wird, und speichert es unter dem Pfad,der in Stringform als zweiter Parameter übergeben wird. Lieferteinen Booleschen Wert, der anzeigt, ob die Operation erfolg-reich war oder nicht.

156 | Kapitel 14: Objektarchivierung

Page 165: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 165/224

- (id)initForWritingWithMutableData:(NSMutableData *)data

Liefert einen initialisierten Coder, der in das übergebene NSData-Objekt schreibt.

– (void) finishEncodingMuss aufgerufen werden, wenn das letzte Objekt archiviertwurde. Sorgt dafür, dass der genutzte Datenspeicher geschlos-sen wird. Nachdem die Archivierung damit beendet wurde,können in einen Speicher keine weiteren Daten geschriebenwerden.

Die korrespondierenden NSKeyedUnarchiver-Methoden sind:+ (id)unarchiveObjectWithData:(NSData *)data

Lädt einen Objektgraphen aus einem NSData-Archivspeicher.

+ (id)unarchiveObjectWithFile:(NSString *)path

Lädt einen Objektgraphen aus einer Datei, die über einenPfadstring angegeben wird.

- (id)initForReadingWithData:(NSData *)dataInitialisiert einen Coder zum Lesen mit einem NSData-Objekt alsSpeicher.

- (void)finishDecoding

Beendet das Lesen auf einem Coder.

Einige BeispieleWenn Sie nur ein Objekt bzw. nur einen Objektgraphen archivierenwollen, können Sie einfach eine der Klassennachrichten nutzen:

id tier = [Tier tierMitName: @"Bertram" art: @"Elefant"alter: 13];

id data = [NSKeyedArchiver archivedDataWithRootObject: tier];

Zur Objektwiederherstellung nutzen Sie dann das entsprechendeNSKeyedUnarchiver-Gegenstück:

kopie = [NSKeyedUnarchiver unarchiveObjectWithData: data];

Wenn Sie mehrere Objekte bzw. mehrere Objektgraphen archi-vieren wollen, erstellen Sie ein Coder-Objekt, das ein geeignetesArchivierungsziel nutzt (hier ein NSData-Objekt):

Coder-Objekte | 157

Page 166: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 166/224

id tier = [Tier tierMitName: @"Bertram" art: @"Elefant"alter: 13];

NSMutableData *data = [NSMutableData new];NSKeyedArchiver *coder = [[NSKeyedArchiver alloc]

initForWritingWithMutableData: data];[coder encodeObject: tier forKey: @"tier"];…[coder finishEncoding];

Wenn Sie keine weiteren Objektgraphen archivieren müssen, schlie-ßen Sie den Archivierungsvorgang ab, indem Sie dem Coder diefinishEncoding-Nachricht senden!

Aus dem gleichen Datenspeicher können Sie die Objekte dannfolgendermaßen wiederherstellen:

NSCoder *decoder = [[NSKeyedUnarchiver alloc]initForReadingWithData: data];

id wiederhergestellt = [decoder decodeObjectForKey: @"tier"];

158 | Kapitel 14: Objektarchivierung

Page 167: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 167/224

KAPITEL 15

Blocks

Blocks sind Objekte, die ausführbare Codeeinheiten repräsentieren.Sie können in Ihrem Code wie Objekte herumgereicht und gespei-chert und wie Funktionen aufgerufen werden. Wie Funktionenhaben sie Argumentlisten und einen Rückgabetyp, der entwederexplizit angegeben oder vom Compiler aus dem Definitionskontextgeschlossen wird. Im Unterschied zu Funktionen können sie mit

dem Zustand des Kontexts interagieren, in dem sie definiert wur-den. Optional können sie ihn auch ändern. Der Compiler sorgtdafür, dass der Zustand des Kontexts, in dem ein Block definiertwurde, erhalten bleibt, solange der Block besteht.

Blocks definieren

Die Deklaration einer Blockreferenz hat die gleiche Struktur wie dieDeklaration eines C-Funktionszeigers:

Ruckgabetyp   (^Variablenname) ( Argumentliste)

Die Definition eines Blockliterals hat folgende Gestalt:

^Ruckgabetyp( Argumentliste) {/*   Anweisungen   */}

Der Rückgabetyp ist optional und muss nur angegeben werden,wenn der Compiler den Rückgabetyp aus der Blockdeklarationnicht korrekt schließen kann. Eine einfache Blockdefinition, dieeinen Block definiert, der eine Objektbeschreibung auf der Konsoleprotokolliert, könnte z. B. so aussehen:

void (^log)(id) = ^(id o){NSLog(@"%@", o);};

| 159

Page 168: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 168/224

Page 169: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 169/224

Page 170: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 170/224

Operationen der aktuellen Instanz zugreifen. Blocks können darü-ber hinaus auf alle Variablen, Parameter und Konstanten zugreifen,die im Definitionskontext gültig sind, zum Beispiel

int a = 5;int (^aPlusB)() = ^{return [self b] + a;};a = aPlusB();

Der Code definiert einen Block, der den Wert einer Instanzeigen-schaft b  und den Wert der lokalen Variablen  a  addiert und zurück-liefert.

Zugriff auf Objektzusta nde

Schauen wir uns zunächst den Zugriff auf Objektzustände anhandeines vollständigeren Beispiels an. Folgende Schnittstelle deklariertdas Fundament einer Klasse, die einen Cursor darstellt. Anstelle vonNachrichten nutzt sie jedoch Blocks, um die Cursorposition zumanipulieren. Dazu wird ein Blocktyp definiert, der als Rück-

gabetyp für die Nachrichten dient, über die der Nutzer der Klassedie Blocks abrufen kann:

typedef void (^VoidVoidBlock) ();@interface Cursor : NSObject {

int pos;}- (VoidVoidBlock)vor;- (VoidVoidBlock)zurueck;- (VoidVoidBlock)position;@end

Die Implementierung könnte folgende Gestalt haben:

@implementation Cursor- (VoidVoidBlock)vor {

return ^{pos++;};};- (VoidVoidBlock)zurueck {

return ^{pos--;};}- (VoidVoidBlock)position {

return ^{NSLog(@"Position %d", pos);};}@end

162 | Kapitel 15: Blocks

Page 171: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 171/224

Die drei Instanznachrichten liefern jeweils einen Block, der unmit-telbar auf die Ivar pos zugreift.

Das ist weniger unsinnig, als es scheint. ZumBeispiel könnte man die Dekrementierungs-und Inkrementierungsblocks unmittelbar alsCallbacks für eine Aktion setzen.

Die so definierte Klasse und ihre Blocks könnte man folgenderma-ßen nutzen. Der Code definiert drei Blockreferenzen mit dem in der

Cursor-Schnittstelle definierten Blocktyp, denen die Blocks zuge-wiesen werden, die die Nachrichten zurückliefern. Über diese wer-den die Blocks dann ausgeführt:

Cursor *cursor = [Cursor new];VoidVoidBlock vor = [cursor vor];VoidVoidBlock zurueck = [cursor zurueck];VoidVoidBlock position = [cursor position];vor();

vor();zurueck();position();

Der Code verhält sich genau so, wie Sie es wahrscheinlich erwartenwürden. Nachdem er ausgeführt wurde, befindet sich der Cursor anPosition 1.

So, wie der Implementierungscode formuliert ist, könnte es denAnschein erwecken, als wären die Blocks selbst Member der Klasse.Deswegen scheint es selbstverständlich, dass der Code funktioniert.Eigentlich sind die Blocks aber unabhängige Objekte, die von denInstanznachrichten zurückgeliefert werden, selbst aber auf denZustand der Instanz zugreifen.

Blocks sind nicht an die Instanz, sondern an den lexikalischen

Kontext gebunden, in dem sie definiert werden. Auf die Instanzdatenund -operationen können sie zugreifen, weil self in den Nachrichtendefiniert ist, in denen sie definiert werden. Das  pos-Feld des  cursor-Objekts kann in den Blocks also genutzt werden, weil  self-Teil desKontexts ist, in dem die Blockobjekte erstellt werden.

Zugriff auf den Kontext | 163

Page 172: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 172/224

Da die Blockoperation nur gewährleistet werden kann, wenn dasObjekt, dessen Zustand manipuliert wird, funktionsfähig ist, mussein Block, der ein Objekt referenziert, eine starke Referenz auf dieses

Objekt darstellen. Die Blocks halten die Objekte, die sie referenzie-ren, also am Leben. Sie werden erst freigegeben, wenn die Blocksfreigegeben wurden, die sie referenzieren.

Der Code funktioniert also, weil die Blocks self einfangen und denpos-Zugriff auf  self auflösen. Würden sie einfach den Wert von  pos

einfangen, würde der Code nicht funktionieren.

Zirkula re Referenzen auf self 

Sie müssen darauf achten, dass Sie Ihre Blocks so gestalten, dass esnicht zu zirkulären Referenzen kommt. Die folgende Schnittstellen-deklaration birgt dieses Risiko:

typedef void (^VoidVoidBlock) ();@interface Cursor : NSObject {

int pos;@publicVoidVoidBlock vor;VoidVoidBlock zurueck;VoidVoidBlock position;

}@end

Die Klasseninstanzen halten starke Referenzen auf die drei Block-objekte. Würden diese nun ihrerseits starke Referenzen auf dieInstanz halten, weil sie   self   referenzieren, würde das zu einerzirkulären Referenz führen. Das wäre bei der folgenden naivenImplementierung der Fall:

@implementation Cursor- (id)init {

pos = 0;vor = ^{pos++;};zurueck = ^{pos--;};position = ^{NSLog(@"Position %d", pos);};

}@end

Die Blocks referenzieren die Ivar pos (was ja nur eine Abkürzung fürself->pos  ist). Die Blocks halten also starke Referenzen auf  self,

164 | Kapitel 15: Blocks

Page 173: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 173/224

self  hält starke Referenzen auf die Blocks und schon haben wirzirkuläre Referenzen, die verhindern, dass die beteiligten Elementefreigegeben werden. Glücklicherweise warnt Sie der Compiler,

wenn er mögliche Referenzendlosschleifen erkennt.Zirkuläre Referenzen brechen Sie üblicherweise, indem Sie einelokale schwache Referenz auf   self  definieren und diese dann imBlock einer starken Referenz zuweisen, auf der Sie dann im Blockoperieren, zum Beispiel (nur für vor):

@implementation Cursor-(id) init {

pos = 0;__weak Cursor *weakSelf = self;vor = ^{

Cursor *c = weakSelf;c->pos++;

};// …

}

@endVersuchen Sie nicht, einen Alias für  self zu nutzen, der eine starkeReferenz darstellt. Der Compiler beschwert sich dann zwar nichtmehr, weil er die Gefahr nicht mehr erkennt, aber die Referenz-endlosschleife haben Sie damit nicht behoben.

Lokale VariablenEin Block kann zwar auf die Variablen, Parameter und Konstantenzugreifen, die in seinem Definitionskontext gültig sind, aber er kannsie nicht einfach so manipulieren. Der Compiler meldet einenFehler, wenn Sie versuchen, den Wert einer solchen Stack-Variablenzu modifizieren. Er sagt Ihnen, dass die Variable nicht zuweisbar ist,wenn Sie z. B. so versuchen, eine lokale Variable in einem Block zumanipulieren:

int a = 0;id plus = ^(int b){a+=b;}; // FEHLER

Das liegt daran, dass Blocks üblicherweise nur den Wert der Varia-blen bei der Definition des Blocks einfangen. Zum Beispiel wirkt

Lokale Variablen | 165

Page 174: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 174/224

sich eine spätere Änderung der lokalen Variablen auch nicht auf denWert aus, den der Block bei der Erstellung eingefangen hat:

int a = 0;

void (^out)() = ^{NSLog(@"Wert von a: %d", a);};a++;((void (^)())out)(); // Gibt 0 aus, nicht 1!

Wenn der Block auf eine Objektreferenz zugreift, können Sie imBlock natürlich problemlos das Objekt über diese Referenz mani-pulieren. Block und Kontext arbeiten mit dem gleichen Wert, derAdresse des Objekts. Die Manipulation der lokalen Objektvariablen

erfolgt also unter den gleichen Bedingungen wie die Manipulationvon self in einer Klasseninstanz. Aber wenn Sie der lokalen Objekt-variablen ein neues Objekt zuweisen, dann referenzieren Block undObjekt unterschiedliche Objekte, zum Beispiel:

id liste = [NSMutableArray new];void (^addObject)(id) = ^(id o) {

[liste addObject: o];

};void (^print)() = ^{NSLog(@"Block %@", liste);};addObject(@1);addObject(@2);NSLog(@"Lokal %@", liste);print();liste = @"123";print();

Dieser Code definiert ein veränderliches Array und zwei Blocks, diedieses Array referenzieren. Der eine fügt ihm Elemente hinzu, derandere gibt es aus. Solange die liste-Referenz nicht verändert wird,sind alle Änderungen, die an dem Array-Objekt vorgenommenwerden, in den Blocks und im lokalen Kontext sichtbar. Aberwenn der liste ein anderes Objekt zugewiesen wird, operieren diebeiden Blocks weiterhin auf der Referenz, die sie bei der Erstellung

als Wert erhielten. Die Ausgabe dieses Codes sähe (umformatiert)so aus:

Lokal (1, 2)Block (1, 2)Block (1, 2)

liste  referenziert ein anderes Objekt, aber der   print-Block greiftweiter auf das ursprüngliche Array-Objekt zu. Es könnte auch

166 | Kapitel 15: Blocks

Page 175: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 175/224

weiterhin über add manipuliert werden, da die beiden Blocks dafürsorgen, dass das ursprüngliche Objekt nicht freigegeben wird.

BlockvariablenWenn der Block nicht den Wert, sondern die Variable selbst ein-fangen soll, muss die Variable explizit mit dem Variablenqualifizie-rer _ _block als Blockvariable markiert werden:

_ _block int a = 0;void (^out)() = ^{NSLog(@"Wert von a: %d", a);};

a++;((void (^)())out)(); // Gibt 1 aus

Mit   _ _block   als Blockvariablen markierte Variablen können inBlocks dann auch verändert werden:

_ _block int a = 0;id plus = ^(int b){a+=b;}; //Kein Fehler mehr

Diese Markierung als Blockvariable ist erforderlich, weil der Com-piler dafür sorgen muss, dass die Variable dem Block per Referenzübergeben wird, wenn sich die Änderungen an der Variablen imBlock auf den Wert der Variablen im Definitionskontext auswirkensoll und umgekehrt. Blocks verhalten sich in dieser Hinsicht dannalso vollkommen anders als Funktionen oder Nachrichten. Dieseerhalten stets eine Kopie des Werts der Variablen. Änderungen des

Werts in der Funktion oder Nachricht wirken sich nie auf denursprünglichen Wert aus.

Schauen wir uns das anhand einer Abwandlung unseres Cursor-Bei-spiels an. Folgender Code definiert eine Blockvariable pos, die vonzwei Blocks,  vor  und  zurueck, manipuliert wird. Die Änderungenam Wert der Variablen, die in den Blocks vorgenommen werden,wirken sich auf den Wert der ursprünglichen Variablen aus. Ände-

rungen an der Variablen werden von den Blocks gesehen:_ _block int pos = 0;VoidVoidBlock vor = ^{pos++;};VoidVoidBlock zurueck =^{pos--;};vor(); // pos = 1vor(); // pos = 2zurueck(); // pos = 1

Lokale Variablen | 167

Page 176: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 176/224

pos = 5;zurueck() // pos = 4

Blocks, die auf diese Weise lokale Zustände einfangen, können als

Closures verwendet werden, wenn sie aus dem lokalen Geltungs-bereich zurückgeliefert oder als Argument an eine andere Methodeübergeben werden. Der eingefangene Zustand bleibt so lange erhal-ten, bis der Block freigegeben wird.

Blockvariablen haben noch eine weitere interessante Eigenschaft:Sie können den Speicherort wechseln. Die Blockvariable   pos   istzunächst eine gewöhnliche Stack-Variable. Aber nachdem das erste

Blockliteral definiert und einer starken Referenz zugewiesen wurde,wird sie in eine Heap-Variable umgewandelt. Das können Sie sehen,wenn Sie sich die jeweils aktuelle Speicheradresse von pos ansehen:

_ _block int pos = 0;NSLog(@"%p", &pos); // Stack, z. B.: 0x7fff5fbff878VoidVoidBlock vorOp = ^{pos++;};NSLog(@"%p", &pos); // Heap, z. B.: 0x1003013b8

Das erfolgt, wenn ein Block, der auf eine Blockvariable zugreift, auf den Heap kopiert wird, was unter ARC automatisch passiert, wennder Block einer Variablen zugewiesen wird, die eine starke Referenzdarstellt.

Globale und kontextgebundene BlocksBlockdefinitionen sind zwar Objektliterale, weisen aber einen ent-scheidenden Unterschied zu anderen Objektliteralen wie String-literalen auf. Stringliterale sind Kompilierungskonstanten, die ein-mal ausgewertet und zur Laufzeit nur noch referenziert werden. DaBlockliterale mit ihrem Definitionskontext interagieren können, derbei jeder Ausführung anders sein kann, müssen Blockliterale bei

 jeder Ausführung neu ausgewertet werden. Bei jeder Ausführungdes Codes muss also ein neues Blockobjekt erstellt werden. Weil dasäußerst ressourcenaufwendig wäre, gibt es zwei Arten von Blocks,

 globale und kontextgebundene.

Globale Blocks sind Blocks ohne Kontext. Sie werden entwederunmittelbar global auf oberster Programmebene definiert oder vomCompiler als Optimierungsmaßnahme erstellt. Globale Blocks wer-

168 | Kapitel 15: Blocks

Page 177: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 177/224

den erzeugt, wenn der Compiler feststellt, dass ein Block nicht mitdem   lokalen   Kontext interagiert, in dem er definiert wird. Sieverhalten sich wie die Objekte, die auf Basis anderer Literalformen

erstellt werden. Es gibt nur eine Kopie eines globalen Blocks, die auf dem Heap gespeichert ist. Ein Beispiel:

NSMutableArray *liste = [NSMutableArray new];for (int i = 0; i < 3; i++) {

[liste addObject:^{NSLog(@"Globaler Block");}];}

In der Schleife wird den ersten drei Elementen des Arrays ein

Blockobjekt hinzugefügt. Da sich der Kontext bei jedem Schleifen-durchlauf ändert, müsste eigentlich bei jedem Durchlauf das indiesem Kontext definierte Blockliteral neu ausgewertet werden.Aber der Compiler erkennt, dass der Block nicht auf den Kontextzugreift, und erstellt deswegen ein globales Blockobjekt. Die dreiElemente im Array sind also drei Referenzen auf dasselbe Objekt.Das zeigt die folgende Ausgabe, die einfach die Beschreibung der

drei Blockobjekte NSLog(@"%@", block); enthält:<__NSGlobalBlock__: 0x100005b50><__NSGlobalBlock__: 0x100005b50><__NSGlobalBlock__: 0x100005b50>

Wie Sie sehen, werden globale Blocks intern also durch __NSGlobal

Block__-Objekte repräsentiert, die im gleichen Speicherbereich wiedie anderen Objekte, das heißt auf dem Heap, festgehalten werden.

Kontextgebundene Blocks sind Blocks, die mit dem lexikalischenKontext interagieren, in dem sie definiert werden. Wenn ein Blockmit seinem Definitionskontext interagiert, muss das Blockliteraltatsächlich bei jeder Ausführung des Codes neu ausgewertet wer-den. Wie bei gewöhnlichen lokalen Werten gibt es bei jeder Aus-führung einen neuen »Stack-Wert«.

Wenn Ihr Code unter ARC läuft, lässt sich das nur schwer demons-trieren. Blockobjekte werden zwar auf dem Stack erstellt, unterARC bei der Zuweisung an eine Variable, die eine starke Bindungdarstellt, oder beim Einfügen in ein Array usw. aber  auf den Heapkopiert. Das sorgt dafür, dass Sie sich bei ARC eigentlich niedarüber Gedanken machen müssen, wie die Stack-Objekte, die

Globale und kontextgebundene Blocks | 169

Page 178: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 178/224

Blocks eigentlich darstellen, über den Kontext hinaus erhaltenbleiben, in dem sie definiert wurden.

Betrachten Sie die folgende nur leicht abgewandelte Form des

obigen Beispiels:NSMutableArray *liste = [NSMutableArray new];for (int i = 0; i < 3; i++) {

[liste addObject:^{NSLog(@"%d. Kontextgebundener Block",i);}];}

Das hier definierte Blockobjekt greift auf die Schleifenvariable i und

damit auf den Kontext der Schleife zu. Deswegen wird bei jederAusführung ein neues kontextgebundenes Blockobjekt auf demStack erstellt, das dann bei der Einfügung in das Array auf denHeap kopiert wird. Wenn Sie sich die Beschreibung dieser Block-objekte ausgeben lassen, sehen Sie an den abweichenden Speicher-adressen, dass es sich um drei eigenständige Objekte des Typs__NSMallocBlock__ handelt:

<__NSMallocBlock__: 0x10010f110>0. Kontextgebundener Block<__NSMallocBlock__: 0x10010f140>1. Kontextgebundener Block<__NSMallocBlock__: 0x10010f170>2. Kontextgebundener Block

Unter der Blockbeschreibung sehen Sie, was bei der Ausführung des

 jeweiligen Blockobjekts ausgegeben wird. Die Blockobjekte fangenden jeweils aktuellen Wert der Schleifenvariablen i ein.

Dass Blockobjekte eigentlich Stack-Objekte sind und welche Ver-pflichtungen das mit sich bringt, sieht man, wenn man den gleichenCode unter MRC ausführt. Die Ausgabe hätte dann folgende Ge-stalt:

// Ausgabe bei Ausfuhrung unter MRC<__NSStackBlock__: 0x7fff5fbff300>2. Kontextgebundener Block<__NSStackBlock__: 0x7fff5fbff300>2. Kontextgebundener Block<__NSStackBlock__: 0x7fff5fbff300>2. Kontextgebundener Block

170 | Kapitel 15: Blocks

Page 179: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 179/224

Es werden drei __NSStackBlock__-Objekte erstellt, bei jedem Schlei-fendurchlauf ein neues. Aber da diese auf dem Stack erstellt und ander gleichen Speicheradresse abgelegt werden, überschreiben die

später erstellten die zuvor erstellten Blockobjekte. Die Zeiger imArray, die alle auf dieselbe Adresse zeigen, greifen dann nur nochauf die zuletzt erstellte Kopie zu. Deswegen wird immer derselbeBlock ausgeführt und der dort aktuelle Wert der Schleifenvariablenausgegeben.

Blocks kopieren

Unter MRC müssen Sie sich selbst darum kümmern, dass Blocks auf den Heap kopiert werden, damit sie über ihren Definitionskontexthinaus erhalten bleiben, zum Beispiel:

for (int i = 0; i < 4; i++) {[liste addObject:[ [^{NSLog(@"%d. Kontextgebundener Block",

i);}   copy] autorelease]];}

Das gilt z. B. auch, wenn Blockobjekte aus einer Methode zurück-geliefert werden (was unter ARC ebenfalls kein Problem ist). Bei-spielsweise würde Folgendes zu einem Laufzeitfehler führen, wennversucht würde, den zurückgelieferten Block auszuführen:

-(id)zaehlerBlock {int a = 0;

return ^(){return i++;};}

Der Block muss mit  copy  auf den Heap kopiert werden, damit erüber den Definitionskontext erhalten bleibt:

-(id)zaehlerBlock {int a = 0;return   [ [^(){return i++;}   copy] autorelease];

}

Bei   __NSGlobalBlock__- und   __NSMallocBlock__-Objekten liefert-copy   einfach   self. Beachten Sie, dass   -copy  den Referenzzählernicht erhöht. Dazu müssen Sie die üblichen MRC-Speicherverwal-tungsnachrichten nutzen. Der Code oben liefert, dem Nachrichten-

Globale und kontextgebundene Blocks | 171

Page 180: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 180/224

namen entsprechend, ein Blockobjekt, das automatisch freigegebenwird.

Die Blocks-API definiert zwei Makros, die zum Kopieren und Frei-

geben von Blockobjekten eingesetzt werden können:  Block_copy()und   Block_release(). Diese können Sie anstelle der Objective-C-Speicherverwaltungsnachrichten nutzen. Wenn Sie diese Makroseinsetzen, sollten Sie darauf achten, dass Sie beide Technologien beider Behandlung eines Blocks nicht mischen.

Unter ARC sollten Sie eigentlich nicht in eine Situation kommen, in

der Sie einen Block manuell kopieren müssen.

172 | Kapitel 15: Blocks

Page 181: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 181/224

KAPITEL 16

NSObject-Referenz

Die nachfolgende Referenz ist keine vollständige Referenz zu  NSOb

ject. Sie führt die Nachrichten auf, die Sie am häufigsten benötigenwerden. Die Einträge enthalten jeweils die vollständige Nachrich-tensignatur und eine Kurzbeschreibung. Nachrichten, die die glei-chen Funktionalitäten stellen, werden in der Regel in einem ein-zigen Eintrag behandelt.

Zu Anfang jedes Abschnitts ist der Aufgabenbereich vermerkt, fürden diese Nachricht gedacht ist. Zu vielen Nachrichten finden Sie inden vorangegangenen Abschnitten gleichen Namens weitere Erläu-terungen und Verwendungsbeispiele.

+ (BOOL)accessInstanceVariablesDirectly

Key/Value-Coding. Der Rückgabewert dieser Methode steuert,

ob beim KVC-Zugriff auf eine Eigenschaft direkt auf eineInstanzvariable zugegriffen werden soll, wenn es keine Zugriffs-methode gibt. Die Standardimplementierung liefert YES,d.h.,eswird direkt auf Instanzvariablen zugegriffen. Das bedeutet, dassdie Kapselung von Instanzvariablen durch KVC umgangenwerden kann. Überschreiben Sie diese Methode und lassen Siesie NO liefern, wenn Sie das verhindern wollen.

+ (id)alloc+ (id)allocWithZone:(NSZone *)zone

Objektlebenszyklus. Liefert eine Referenz auf neu allozierte undvorinitialisierte Instanzen der Empfängerklasse. Die Verwend-barkeit dieser Instanz ist nicht garantiert, da alle Instanzvaria-blen nur mit den typgemäßen Vorgabewerten initialisiert wer-den. Vor der Verwendung müssen allozierte Instanzen zunächst

| 173

Page 182: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 182/224

mit einer Methode der   init-Familie initialisiert werden. Die+allocWithZone:-Nachricht ist ein historisches Relikt. Sie wirdintern von alloc aufgerufen. Der zone-Parameter wird ignoriert.

- (id)autoreleaseSpeicherverwaltung. Übergibt das Objekt an den zuletzt erstell-ten (bzw. den innersten) Auto-Release-Pool. Die Freigabe (dieReduzierung des Referenzzählers) erfolgt, wenn der entspre-chende Pool geleert wird. Unter ARC ist diese Nachricht nichtzulässig.

- (Class)class+ (Class)class

Laufzeitinformation. Liefert das Class-Objekt für die Klasse desEmpfängers.

- (BOOL)conformsToProtocol:(Protocol *)aProtocol

+ (BOOL)conformsToProtocol:(Protocol *)aProtocol

Laufzeitinformation. Prüft, ob der Empfänger dem als Argu-

ment übergebenen Protokoll entspricht. Liefert  YES, wenn dasder Fall ist, andernfalls  NO. Die Klassenmethode prüft nur, obdie Protokollentsprechung deklariert wird. Sie prüft nicht, obder Empfänger tatsächlich auf die vom Protokoll deklariertenNachrichten reagiert. Die Instanzmethode prüft, ob die Instanztatsächlich auf die Nachrichten reagiert, die das Protokoll de-klariert. Das von beiden Nachrichten als Argument erwartete

Protocol-Objekt kann mithilfe der Direktive @protocol() ange-geben werden.

- (id)copy

Objektlebenszyklus. Liefert eine Kopie des Objekts zurück,wenn die Klasse das  NSCopying-Protokoll unterstützt.  -copy isteine Hilfsmethode, die einfach die   NSCopying-Methode

-copyWithZone: aufruft. Gibt es eine  -copyWithZone:-Methode,wird ihr Rückgabewert zurückgeliefert, gibt es keine, wird dieProgrammausführung standardmäßig mit einer Ausnahme ab-gebrochen.

+ (id)copyWithZone:(NSZone *)zone

Objektlebenszyklus. Liefert einfach  self  zurück, keine Kopie!Das ist keine Implementierung des  NSCopying-Protokolls, son-

174 | Kapitel 16: NSObject-Referenz

Page 183: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 183/224

dern eine Hilfsmethode, die es ermöglicht,  Class-Objekte dortzu nutzen, wo NSCopying-kompatible Objekte benötigt werden.Diese Einrichtung wird von Framework-Elementen wie der

Klasse   NSDictionary   genutzt. Benutzerdefinierte Klassen, dieeine ähnliche Einrichtung bieten wollen, müssen die Unterstüt-zung dieser Methode explizit prüfen, da ihre Unterstützung mitconformsToProtocol: nicht festgestellt werden kann. Das  zone-Argument wird ignoriert.

- (void)dealloc

Objektlebenszyklus. Gibt den vom Empfänger eingenommenen

Speicher frei. Darf unter ARC implementiert, aber nicht auf-gerufen werden.

- (NSString *)description

Laufzeitinformation. Liefert einen String, der eine Beschreibungdes Empfängers enthält.

- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys

Key/Value-Coding. Liefert ein NSDictionary mit den Schlüssel/Wert-Paaren zu den Schlüsseln, die über das Array  keys ange-geben werden. Ruft für alle Schlüssel in  keys objectValueFor

Key: auf und ordnet dem Schlüssel den Wert  NSNull zu, wennder Rückgabewert nil ist.

- (id)forwardingTargetForSelector:(SEL)aSelector

Messaging. Wird von der Laufzeitumgebung vor  -forwardInvocation   aufgerufen, wenn eine Nachricht unbekannt ist, undsollte ein anderes Objekt liefern, an das die Laufzeit die unbe-kannte Nachricht unmittelbar weiterleiten soll. Erhält als Argu-ment den Selektor der Nachricht, für die keine Implementie-rung gefunden wurde.

- (void)forwardInvocation:(NSInvocation *)anInvocation

Messaging. Wird von der Laufzeitumgebung aufgerufen, wenneine Nachricht unbekannt ist. Diese Nachricht bietet dem Emp-fänger eine Möglichkeit, unbekannte Nachrichten weiterzulei-ten, z. B. an einen anderen Empfänger. Das Argument ist einNSInvocation-Objekt, das die Nachricht beschreibt, für diekeine Implementierung gefunden wurde.

NSObject-Referenz | 175

Page 184: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 184/224

- (NSUInteger)hash

Liefert einen Hashwert für das Objekt. Der Hashwert ist einganzzahliger Wert, der eine hinreichend eindeutige Darstellung

eines Objekts bietet. Der Hashwert von zwei Objekten, die alsgleich betrachtet werden, sollte gleich sein. Aus der Gleichheitdes Hashwerts für zwei Objekte kann man aber nicht dieGleichheit der Objekte schließen.

- (id)init

Objektlebenszyklus. Initialisiert ein Objekt und liefert es zu-rück. Das zurückgelieferte Objekt muss nicht mit dem identisch

sein, dem die Nachricht gesendet wurde. Alle weiteren Opera-tionen sollten deswegen immer den Rückgabewert dieser Nach-richt nutzen. Die NSObject-Implementierung macht nichts undliefert einfach self zurück. Andere Klassen überschreiben init,um Instanzen den Anforderungen der Klasse gemäß zu initiali-sieren, nachdem sie mit   alloc  erstellt wurden. Üblicherweisewerden die beiden Nachrichten folgendermaßen verkettet:

Klasse   *variable   = [[Klasse   alloc] init];

+ (void)initialize

Klasseninitialisierung. Wird zur Initialisierung der Empfänger-klasse aufgerufen, bevor sie genutzt wird. Die Laufzeit-umgebung garantiert, dass der Klasse diese Nachricht gesendetwird, bevor Anwendungscode ihr oder einer ihrer Unterklassen

irgendeine andere Nachricht sendet. Das wird von der Laufzeit-umgebung so durchgeführt, dass Oberklassen die Nachricht vorUnterklassen erhalten. Überschreiben Sie diese Nachricht,wenn Sie Initialisierungsschritte durchführen müssen, die fürdie gesamte Klasse nur einmal erfolgen dürfen, z. B. um einestatische Variable zu initialisieren.

+ (NSMethodSignature *)

instanceMethodSignatureForSelector:(SEL)aSelector

Messaging. Liefert eine Referenz auf das NSMethodSignature-Ob- jekt, das die Signatur der Instanzmethode beschreibt, die durchdas Selektorargument angegeben wird, oder   nil, wenn keineentsprechende Methode gefunden werden kann.

176 | Kapitel 16: NSObject-Referenz

Page 185: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 185/224

Page 186: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 186/224

+ (BOOL)isSubclassOfClass:(Class)aClass

Laufzeitinformation. Liefert  YES, wenn die Klasse des Empfän-gers der als Argument übergebenen Klasse entspricht bzw. eine

Unterklasse der übergebenen Klasse ist.+ (void)load

Klasseninitialisierung. Wird von der Laufzeitumgebung auf-gerufen, wenn ihr eine Klasse oder Kategorie hinzugefügt wird.+load  wird dynamisch geladenen und statisch eingebundenenKlassen und Kategorien gesendet, die +load selbst implementie-ren. Geerbte  +load-Implementierungen werden nicht aufgeru-

fen. Für eine Klasse kann  +load  mehrfach implementiert sein:einmal für die Klasse selbst und einmal für jede Kategorie.Oberklassen erhalten die Nachricht vor ihren Unterklassen,und die +load-Implementierung der Klasse wird vor den +load-Implementierungen von Kategorien aufgerufen. ÜberschreibenSie +load, wenn Sie beim Laden einer Klasse oder ihrer Katego-rien spezielle Schritte unternehmen wollen.

- (IMP)methodForSelector:(SEL)aSelector

Messaging. Liefert einen Zeiger auf die Implementierung derInstanz- oder Klassenmethode, die durch den übergebenenSelektor angegeben wird. Der Selektor darf nicht  null sein undmuss einen gültigen Selektor für den Empfänger darstellen.Andernfalls meldet die Methode einen Fehler. Senden Sie diese

Nachricht der Klasse, wenn Sie die Implementierung einerKlassenmethode benötigen, bzw. einer Instanz, wenn Sie dieImplementierung einer Instanzmethode benötigen.

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

Messaging. Liefert einen Zeiger auf ein  NSMethodSignature-Ob- jekt, das die Methodensignatur der Methode beschreibt, diedurch den als Argument übergebenen Selektor identifiziert

wird. Muss entsprechend implementiert werden, wenn-forwardInvocation: überschrieben wird, da die Methodensig-natur zum Aufbau des NSInvocation-Objekts benötigt wird, das-forwardInvocation: als Argument enthält.

178 | Kapitel 16: NSObject-Referenz

Page 187: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 187/224

– (NSMutableArray *) mutableArrayValueForKey: (String *) key

– (NSMutableArray *) mutableArrayValueForKeyPath: (String *)

keyPath

- (NSMutableSet *)mutableSetValueForKey:(NSString *)key– (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath

- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:

(NSString *)key

- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:

(NSString *)keyPath

Key/Value-Coding. Diese Methoden liefern jeweils ein ver-

änderliches Objekt des entsprechenden Collection-Typs(NSMutableArray,   NSMutableSet,   NSMutableOrderedSet), das alsProxy für das 1:m-Verhältnis dient, das über den angegebenenSchlüssel/Schlüsselpfad identifiziert wird. Die Standardimple-mentierungen nutzen die üblichen KVC-Namenskonventionenund sollten auf eine Eigenschaft kompatiblen Typs zugreifen.Alle Änderungen an diesem Proxyobjekt wirken sich unmittel-

bar auf das Objekt aus, das hinter diesem 1:m-Verhältnis steht.Rufen Sie z. B. mit   mutableArrayValueForKey  den Wert einerNSArray-Eigenschaft ab, erhalten Sie ein NSMutableArray-Objekt,mit dem Sie das von der Eigenschaft referenzierte NSArray-Ob-

 jekt unmittelbar modifizieren können, zum Beispiel:

id hubert = [ [Spieler alloc] initMitName: @"Hubert"];id waffen = [hubert mutableArrayValueForKey: @"waffen"];

[waffen addObject: @"Schwert"];

hubert.waffen entspricht nun @[@"Schwert"].

- (id)mutableCopy

Objektlebenszyklus. Liefert eine veränderliche Kopie des Ob- jekts zurück, wenn der Empfänger das  NSMutableCopying-Pro-tokoll unterstützt.  -mutableCopying   ist eine Hilfsmethode, die

einfach die  NSMutableCopying-Methode   -mutableCopyWithZone:aufruft. Sie liefert den Rückgabewert von -mutableCopyWithZone:

zurück, wenn der Empfänger  NSMutableCopying   implementiert.Andernfalls löst sie standardmäßig eine Ausnahme aus.

NSObject-Referenz | 179

Page 188: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 188/224

+ (id)mutableCopyWithZone:(NSZone *)zone

Objektlebenszyklus. Liefert einfach self zurück, keine Kopie! Dasist keine Implementierung des  NSMutableCopying-Protokolls, son-

dern eine Hilfsmethode, die es ermöglicht, Class-Objekte dort zunutzen, wo  NSMutableCopying-kompatible Objekte benötigt wer-den. Das zone-Argument wird ignoriert (siehe +copyWithZone:).

+ (id)new

Objektlebenszyklus. Alloziert und initialisiert eine neue Instanzder Empfängerklasse und liefert sie zurück.   [Klasse   new]   ent-spricht [ [Klasse alloc] init]. +new wird in der Objective-C-Welt

selten verwendet, ist der alloc/init-Kombination aber vollkom-men äquivalent, wenn init der designierte Initialisierer ist.

- (id)performSelector:(SEL)aSelector

- (id)performSelector:(SEL)aSelector withObject:(id)anObject

- (id)performSelector:(SEL)aSelector

withObject:(id)anObject

withObject:(id)anotherObjectMessaging. Sendet dem Empfänger dynamisch eine Nachrichtund liefert das Ergebnis des Aufrufs dieser Nachricht. Die -per

formSelector-Nachrichten sind einem direkten Senden der überdie Argumente kodierten Nachricht äquivalent. Nutzen Sie sie,wenn die zu sendende Nachricht von Laufzeitbedingungenabhängig ist. Als erstes Argument erwarten alle Versionen einen

Selektor, der die Nachricht beschreibt. Nutzen Sie die ersteVersion für Nachrichten ohne Argumente, die zweite für Nach-richten mit einem Argument und die dritte für Nachrichten mitzwei Argumenten. Die   withObject-Parameter geben die Argu-mente für die Nachricht an. Mit diesen Nachrichten können nurNachrichten kodiert werden, die null bis zwei Objektargumenteerwarten und einen Objektwert als Ergebnis liefern.

- (oneway void)releaseSpeicherverwaltung. Gibt das Objekt frei und hebt eine Auf-bewahrungsanforderung auf (vermindert den Referenzzähler).Unter ARC ist diese Nachricht nicht zulässig.

180 | Kapitel 16: NSObject-Referenz

Page 189: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 189/224

+ (BOOL)resolveInstanceMethod:(SEL)name

+ (BOOL)resolveClassMethod:(SEL)name

Messaging. Diese beiden Methoden können von der Laufzeit

aufgerufen werden, wenn keine Implementierung für eineNachricht gefunden werden kann. Sie bieten einer Klasse dieMöglichkeit, dynamisch eine Implementierung für die entspre-chende Nachricht zu erstellen. Bei einer Instanznachricht wird+resolveInstanceMethod aufgerufen, bei einer Klassennachricht+resolveClassMethod. Das Argument ist bei beiden Methodender unbekannte Selektor; der Rückgabewert sollte jeweils an-

zeigen, ob dem Objekt dynamisch eine Methodenimplementie-rung hinzugefügt wurde (YES) oder nicht (NO). Die Laufzeitprüft, ob dem Objekt tatsächlich eine Methode hinzugefügtwurde, und meldet eine Warnung, wenn Methodenimplemen-tierung und Rückgabewert nicht im Einklang sind.

- (BOOL)respondsToSelector:(SEL)aSelector

Laufzeitinformation, Messaging. Prüft, ob der Empfänger den

als Argument übergebenen Selektor unterstützt. Liefert   YES,wenn das der Fall ist, andernfalls NO. Ein Empfänger unterstützteinen Selektor üblicherweise, wenn er eine korrespondierendeMethode erbt oder selbst implementiert. -respondsToSelector:

berücksichtigt aber auch dynamische Methodenimplementie-rungen, die von  +resolveInstanceMethod:  bzw.   +resolveClass

Method: gestellt werden. Wenn ein Empfänger die Weiterleitung

von Nachrichten unterstützt, wird das von   +respondsToSelector: nicht widergespiegelt. Gegebenenfalls sollten Sie über-legen,   -respondsToSelector:   entsprechend zu überschreiben.Wenn Sie wissen wollen, ob die Klasse eine Methode unter-stützt, können Sie  -respondsToSelector  auf dem  Class-Objektaufrufen, das diese Klasse repräsentiert.

- (id)retainSpeicherverwaltung. Fordert, dass das Objekt für den Benutzeraufbewahrt wird (erhöht den Referenzzähler um eins). UnterARC ist diese Nachricht nicht zulässig.

NSObject-Referenz | 181

Page 190: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 190/224

- (NSUInteger)retainCount

Speicherverwaltung. Liefert die Anzahl der Aufbewahrungs-anforderungen (den Wert des Referenzzählers). Unter ARC ist

diese Nachricht nicht zulässig.- (void)setNilValueForKey:(NSString *)key

Key/Value-Coding. Wird von den Standardimplementierungender   set…-Methoden aufgerufen, wenn für eine skalare Eigen-schaft der Wert nil übergeben wird. Die Standardimplementie-rung löst eine NSInvalidArgumentException aus.

- (void)setValue:(id)value forKey:(NSString *)key- (void)setValue:(id)value forKeyPath:(NSString *)keyPath

Key/Value-Coding. Setzt den Wert der über den String key bzw.keyPath angegebenen Eigenschaft.

- (void)setValue:(id)value forUndefinedKey:(NSString *)key

Key/Value-Coding. Wird von den anderen set…-Methoden auf-gerufen, wenn ein Schlüssel nicht auf einen Setter bzw. eine

Instanzvariable abgebildet werden kann. Die Standardimple-mentierung löst eine NSUndefinedKeyException aus.

- (void)setValuesForKeysWithDictionary:

(NSDictionary *)keyedValues

Key/Value-Coding. Setzt die Werte der Objekteigenschaften,die durch die Schlüssel des übergebenen  NSDictionary angege-

ben werden, auf die den Dict-Schlüsseln zugeordneten Werte.Die Standardimplementierung ruft für die einzelnen Schlüssel/Wert-Paare im Dict setValue:forKey auf und ersetzt alle NSNull-Werte im Dict durch nil.

- (Class)superclass

+ (Class)superclass

Laufzeitinformation. Liefert das   Class-Objekt, das die Ober-

klasse des Empfängers beschreibt.

- (id)valueForKey: (String *) key

- (id)valueForKeyPath: (String *) keyPath

Key/Value-Coding. Ruft den Wert für das über den Schlüssel-bzw. Schlüsselpfadstring angegebene 1:1- oder 1:m-Verhältnisab. Die Standardimplementierung liefert den Wert einer Eigen-

182 | Kapitel 16: NSObject-Referenz

Page 191: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 191/224

schaft bzw. Instanzvariablen gleichen Namens. Wenn  key bzw.keyPath eine skalare Eigenschaft identifiziert, wird der Wert ineinen passenden NSValue-Typ verpackt.

- (id)valueForUndefinedKey:(NSString *)keyKey/Value-Coding. Diese Methode wird von den Standard-implementierungen der anderen Methoden aufgerufen, wennder Schlüssel nicht auf einen Getter bzw. eine Instanzvariableabgebildet werden kann. Die Standardimplementierung lösteine NSUndefinedKeyException aus.

NSObject-Referenz | 183

Page 192: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 192/224

Page 193: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 193/224

KAPITEL 17

Compilerdirektiven

Die folgende Liste enthält sämtliche Compilerdirektiven, die inObjective-C genutzt werden. Die meisten davon wurden bereits inanderen Teilen dieses Buchs eingesetzt. Manche Direktiven erwar-ten Argumente; einige erwarten ein Argument in runden Klammern,andere einen Codeblock in geschweiften Klammern, wieder anderebeides. Dies wird in der Aufstellung durch Klammern bzw. ge-

schweifte Klammern angezeigt.Zu Anfang jeden Abschnitts ist der Aufgabenbereich vermerkt, fürden diese Compilerdirektive gedacht ist. Zu vielen davon finden Siein den entsprechenden Kapiteln weitere Erläuterungen und Ver-wendungsbeispiele.

@autoreleasepool{}

Speicherverwaltung. Stellt einen neuen Auto-Release-Pool fürden Block zur Verfügung, der mit der Direktive markiert wird.Beim Eintritt in den Block wird der aktuelle Zustand eineseventuell vorhandenen Auto-Release-Pools gespeichert. Wirdder Block normal beendet, wird der für diesen Block geschaffeneAuto-Release-Pool geleert und der gespeicherte Zustand desAuto-Release-Pools wiederhergestellt. Wird die Ausführung des

Blocks durch eine Ausnahme abgebrochen, wird der Pool stan-dardmäßig nicht geleert. Auto-Release-Pool-Blöcke können ge-schachtelt werden.

Die Cocoa-Bibliotheken nutzen die Auto-Release-Einrichtun-gen und erwarten deswegen, dass ein Auto-Release-Pool zurVerfügung steht. Gibt es keinen, führt das unweigerlich zuSpeicherlöchern, sobald Sie die Cocoa-Bibliotheken nutzen. Da

| 185

Page 194: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 194/224

die AppKit- und die UIKit-Event-Loops Auto-Release-Poolsbereitstellen, müssen Sie sich darum bei der GUI-Programmie-rung für Mac OS X bzw. iOS in der Regel nicht selbst kümmern.

Normalerweise brauchen Sie sie nur, wenn Sie neue Threadsstarten bzw. wenn Sie einen lokalen @autoreleasepool-Block zuOptimierungszwecken einsetzen wollen.

@catch() {}

Ausnahme. Markiert einen Ausnahme-Handler. In der Klam-mer muss ein Ausnahmetyp stehen, in der Regel ist das   NSEx

ception *, zum Beispiel:

@catch (NSException *) {…}

Wird statt eines Ausnahmetyps ein vollständiges Ausnahme-argument angegeben, wird diesem das Ausnahmeobjekt zuge-wiesen, das ausgelöst wurde. Das ermöglicht es, im Ausnahme-Handler auf die Informationen zuzugreifen, die der ausgelöstenAusnahme mitgegeben wurden:

catch (NSException *ex) { NSLog(@"%@", ex); }

Auf einen   @try-Block dürfen beliebig viele   @catch()-Blöckefolgen, die unterschiedliche Ausnahmetypen angeben. Der Aus-nahmetyp, den ein @catch()-Block verarbeitet, muss angegebenwerden. Die Klammer darf nicht weggelassen werden oder leersein. Der allgemeinste Ausnahme-Handler ist einer, der den

Ausnahmetyp id deklariert.@class

Deklaration. Vor-Deklaration einer Klasse. Die Direktive wirdeinem Namenstoken oder einer Liste kommaseparierter Na-menstoken vorangestellt und sagt dem Compiler, dass dasentsprechende Namenstoken einen Klassennamen repräsen-tiert. Es wird keine Klassendefinition importiert, sondern nurein Name als Klassenname bekannt gemacht. Solange der Com-piler keine Implementierungsinformationen für diese Klassebenötigt, kann diese Direktive den   #import   der Headerdateiersetzen, in der die Klasse deklariert wird. Das ermöglicht es,#import-Direktiven so nah wie möglich an den Stellen zu halten,in denen die importierten Klassen tatsächlich genutzt werden.

186 | Kapitel 17: Compilerdirektiven

Page 195: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 195/224

In einer Schnittstellendeklaration, die eine Klasse als Ivar-,Eigenschafts-, Argument- oder Rückgabetyp nutzt, werdenz. B. häufig keinerlei Informationen über die Implementierung,

d. h. die Felder, Eigenschaften und Methoden einer Klasse,benötigt. Da dort nur bekannt sein muss, dass das Namens-token eine Klassenangabe repräsentiert, damit der erforderlichePlatz für einen Objektzeiger reserviert werden kann, reicht danneine Vor-Deklaration mit @class aus. In der Implementierungs-datei, in der die Implementierung der vor-deklarierten Klassegenutzt wird, muss dann der Header importiert werden. Die

Implementierung muss z. B. bereits in der Schnittstellendateibekannt sein, wenn eine Klasse als Oberklasse der neu zudefinierenden Klasse dienen soll.

@compatibility_alias

Erstellt einen Alias für eine Klasse. Diese Direktive wird auf derobersten Ebene einer Schnittstellen- oder Implementierungs-datei genutzt. Sie ist, wie der Name sagt, gedacht, um Klassen

zur Kompatibilitätssicherung unter einem anderen Namen an-sprechen zu können. Sie sollten sie nicht wie hier (nur zuBeispielzwecken) vorgeführt nutzen, um sich Tipparbeit beilangen Klassennamen zu ersparen, da das die Lesbarkeit IhresCodes beeinträchtigt (und es für Aliase in Xcode auch keineVervollständigungshilfen gibt):

#import <Foundation/Foundation.h>@combatibility_alias String NSMutableString;int main() {

String *s = [String stringWithString: @"123"];[s appendString: @"4"];// ...

}

@dynamic

Eigenschaft. Deklariert, dass die Implementierung der mit derDirektive markierten Eigenschaft dynamisch zur Laufzeit ange-boten wird. Der Compiler prüft nicht, ob es eine Implementie-rung für die angegebene Eigenschaft gibt, und führt auch keineautomatische Synthetisierung durch.

Compilerdirektiven | 187

Page 196: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 196/224

@end

Deklaration. Schließt eine Deklarationseinheit, die durch eineDirektive wie @implementation oder @interface geöffnet wurde.

@encode()Typkodierung. Erwartet als Argument in der Klammer einObjekt oder einen Objective-C-Typ und substituiert den String,der die Typkodierung für diesen Typ darstellt.

@finally {}

Ausnahme. Letzter Baustein der try-catch-finally-Ausnahmever-

arbeitung. Markiert einen Block, der Operationen definiert, dieausgeführt werden sollen, nachdem ein  @try-Block ausgeführtwurde. Der @finally-Block wird immer ausgeführt, unabhängigdavon, ob der @try-Block erfolgreich ausgeführt werden kann.

Tritt im   @try-Block eine Ausnahme auf, wird der   @finally-Block ausgeführt, nachdem der entsprechende  @catch()-Hand-ler abgearbeitet wurde. Der  @try-Block wird auch ausgeführt,

wenn es keinen passenden  @catch()-Block gibt oder wenn der@catch-Block die Ausnahme mit   @throw   neu auslöst oder im@catch()-Block eine andere Ausnahme ausgelöst wird.

@implementation

Deklaration. Markiert den Anfang der Implementierung für dieKlasse, deren Name auf die Direktive folgt. Ein Implementie-

rungsabschnitt muss durch die @end-Direktive geschlossen wer-den.

@implementation   Klasse// Implementierungscode@end

Es kann mehrere Implementierungsabschnitte für eine Klassegeben, die Kategorien implementieren.

@interface

Deklaration. Markiert den Anfang der Deklaration der Schnitt-stelle der Klasse, deren Name auf die Direktive folgt. Ver-erbungsverhältnisse und Protokollimplementierungen werdenin der Schnittstellendeklaration angeben, zum Beispiel:

@interface   Klasse   :   Oberklasse   <Protokoll1,   Protokoll2>

188 | Kapitel 17: Compilerdirektiven

Page 197: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 197/224

Auf den Klassennamen (und eventuelle Oberklassen und Pro-tokollangaben) kann ein Abschnitt in geschweiften Klammernfolgen, in dem die Ivars der Klasse deklariert werden. Die

Schnittstellendeklaration muss mit der @end-Direktive geschlos-sen werden.

Es kann beliebig viele   @interface-Abschnitte geben, die ver-schiedene Kategorien deklarieren, die eine vorhandene Schnitt-stelle erweitern. Eine Kategoriedeklaration wird angegeben,indem hinter dem Klassennamen in einer Klammer der Katego-riename angegeben wird, zum Beispiel:

@interface   Klasse

Kategorie. Der Compiler meldet eine Warnung, wenn die glei-che Kategorie mehrfach deklariert wird.

Außerdem kann es für eine Klasse beliebig viele Klassenerwei-terungen, anonyme Kategorien, geben. Eine Klassenerweiterungwird durch eine leere Klammer hinter dem Schnittstellennamenangeben:

@interface   Klasse   ()

@optional

Protokolldeklaration. Leitet in einer Protokolldeklaration einenAbschnitt ein, in dem Methoden aufgeführt werden, die optio-nal sind. Die Direktive gilt für alle nachfolgenden Methoden, bissie durch eine   @required-Direktive ersetzt oder die Protokoll-deklaration mit @end geschlossen wird.

@package

Sichtbarkeit von Ivars. Leitet im Ivar-Deklarationsabschnitteiner  @interface-Deklaration einen Abschnitt ein, in dem Me-thoden stehen, die Paketsichtbarkeit haben. Sie gilt für alle

nachfolgenden Methoden, bis sie durch eine der anderen Sicht-barkeitsdirektiven (@public,   @protected  oder   @private) ersetztwird bzw. die Ivar-Deklaration mit } geschlossen wird.

Compilerdirektiven | 189

Page 198: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 198/224

@private

Sichtbarkeit von Ivars. Leitet im Ivar-Deklarationsabschnitteiner  @interface-Deklaration einen Abschnitt ein, in dem Me-

thoden stehen, die privat, also nur in der Klasse sichtbar sind.Sie gilt für alle nachfolgenden Methoden, bis sie durch eine deranderen Sichtbarkeitsdirektiven (@public,   @protected   oder@package) ersetzt wird bzw. die Ivar-Deklaration mit } geschlos-sen wird.

@property

Eigenschaft. Deklariert in einem  @interface-Abschnitt eine Ei-

genschaft. Eine Eigenschaftsdeklaration besteht aus einer Typ-angabe und einem Eigenschaftsnamen sowie einem Satz vonEigenschaftsattributen und wird durch ein Semikolon abge-schlossen. Die Eigenschaftsattribute werden durch Kommatagetrennt in einer auf die Direktive folgende Klammer angege-ben:

@property (weak, readonly) id eigenschaft;

Wenn mehrere Eigenschaften den gleichen Typ und die glei-chen Attribute haben, können sie durch Kommata getrennt miteiner Direktive angegeben werden:

@property (weak, readonly) id eigenschaft1, eigenschaft2;

Wenn keine Eigenschaftsattribute angegeben werden, ist die

Eigenschaft unter ARC vorgabemäßig   strong   und   readwrite,unter MRC hingegen assign und  readwrite. Eigenschaften sindaußerdem standardmäßig atomar.

@protected

Sichtbarkeit von Ivars. Leitet im Ivar-Deklarationsabschnitteiner  @interface-Deklaration einen Abschnitt ein, in dem Me-thoden stehen, die geschützt sind, d. h. in der Klasse und in von

ihr abgeleiteten Klassen sichtbar sind. Sie gilt für alle nach-folgenden Methoden, bis sie durch eine der anderen Sichtbar-keitsdirektiven (@public,  @package  oder  @private) ersetzt wirdbzw. die Ivar-Deklaration mit } geschlossen wird.

190 | Kapitel 17: Compilerdirektiven

Page 199: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 199/224

@protocol

Deklaration. Die   @protocol-Direktive wird in drei Kontextengenutzt, in denen sie jeweils eine andere Bedeutung hat.

1. Wenn auf die Direktive ein Protokollname (und optional eineProtokollliste in spitzen Klammern) folgt, an die eine Liste vonMethodendeklarationen anschließt, die von der Direktive  @end

beendet wird, deklariert die Direktive ein Protokoll:

@protocol   Protokoll   <U bernommenesProtokoll>//Methodendeklarationen@end

2. Wenn die Direktive Teil einer eigenständigen mit einemSemikolon abgeschlossenen Anweisung ist, in der auf sie einNamenstoken oder eine kommaseparierte Liste von Namens-token folgt, wird ein Protokoll bzw. werden mehrere Protokollevor-deklariert (mehr Informationen zur Vor-Deklaration findenSie beim @class-Eintrag), zum Beispiel:

@protocol   Protokoll;

3. Wenn nach der Direktive in einer Klammer ein Protokoll-name folgt, substituiert der Compiler das korrespondierendeProtocol-Objekt. Auf diese Weise wird die Direktive genutzt,um über die NSObject-Nachricht -conformsToProtocol: die Über-einstimmung mit einem Protokoll zu überprüfen, zum Beispiel:

if([Klasse   conformsToProtocol: @protocol(Protokoll)) …

@public

Sichtbarkeit von Ivars. Leitet im Ivar-Deklarationsabschnitteiner  @interface-Deklaration einen Abschnitt ein, in dem Me-thoden stehen, die öffentlich sind. Sie gilt für alle nachfolgendenMethoden, bis sie durch eine der anderen Sichtbarkeitsdirekti-ven (@package, @protected oder @private) ersetzt wird bzw. die

Ivar-Deklaration mit } geschlossen wird.

@required

Protokolldeklaration. Leitet in einer Protokolldeklaration einenAbschnitt ein, in dem Methoden aufgeführt werden, die erfor-derlich sind. Die Direktive gilt für alle nachfolgenden Deklara-

Compilerdirektiven | 191

Page 200: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 200/224

tionen, bis sie durch eine  @optional-Direktive ersetzt oder dieProtokolldeklaration mit @end geschlossen wird.

@selector()

Messaging. Wird bei der Kompilierung durch den Selektor, SEL,mit der Nachricht ersetzt, die als Argument in der Klammerangegeben wird. Das Argument muss unter ARC ein bei derKompilierung bekannter Nachrichtenname sein.

@synchronized(){}

Threading. Die   @synchronized-Direktive erstellt einen Mutex,

über den ein Block synchronisiert wird. Sie erspart Ihnen diemanuelle Erstellung eines spezifischen Lock- oder Mutex-Objekts, indem sie Ihnen gestattet, ein beliebiges Objekt alsSperrobjekt zu nutzen. Wird ein Block in zwei verschiedenenThreads ausgeführt, kann er nur von einem der Threads betre-ten werden, wenn sie über das gleiche Objekt synchronisiertwerden.

@synthesizeEigenschaft. Weist den Compiler an, die Implementierung fürdie in der Schnittstelle deklarierte Eigenschaft, Getter und/oderSetter sowie Hintergrundfeld, zu generieren. Es können meh-rere durch Kommata getrennte zu synthetisierende Eigenschaf-ten angegeben werden, zum Beispiel:

@synthesize a, b;

Eigenschaften müssen nicht explizit mit  @synthesize  syntheti-siert werden. Wird  @synthesize  nicht angegeben, synthetisiertder Compiler die Eigenschaft automatisch. Sie müssen dieDirektive nur noch einsetzen, wenn Sie das verwendete Hinter-grundfeld selbst festlegen wollen. Beachten Sie, dass die expli-zite und die automatische Synthetisierung Hintergrundfelder

mit unterschiedlichen Namen verwenden!

@throw

Ausnahme. Löst eine Ausnahme aus. Auf die Direktive folgt einAusdruck, der zu einem Objekt ausgewertet wird, das dem@catch()-Handler übergeben wird, der die Ausnahme verarbei-tet. In der Regel ist dieses Objekt ein  NSException-Objekt, aber

192 | Kapitel 17: Compilerdirektiven

Page 201: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 201/224

es kann ein beliebiger Objektwert sein. In einem   @catch()-Handler kann   @throw  ohne Argument verwendet werden, umdie aktuelle Ausnahme mit dem aktuellen Ausnahmeobjekt als

Argument neu auszulösen.@try{}

Ausnahme. Markiert einen Block, in dem die Ausnahmever-arbeitung aktiv ist. Tritt in einem   @try-Block eine Ausnahmeauf, springt die Ausführung unmittelbar in den ersten  @catch-Block, dessen Argumenttyp mit dem Typ des Ausnahmeobjektskompatibel ist. Gibt es keinen passenden @catch-Block, gilt die

Ausnahme als unverarbeitet und wird im Aufrufstapel nachoben geleitet.

Compilerdirektiven | 193

Page 202: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 202/224

Page 203: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 203/224

KAPITEL 18

Alternative Plattformen

Wenn man mit Objective-C programmieren will, braucht man dreiDinge: einen Compiler, eine Laufzeitumgebung und eine Klassenbi-bliothek. Für alles gibt es Alternativen jenseits des Apple-Teller-rands. Die wichtigeren davon werden unten aufgeführt.

Aufgrund der Vielzahl der Werkzeuge, Platt-

formen und Systemkonfigurationen sowie desstetigen Wandels, dem diese unterworfen sind,haben wir hier darauf verzichtet, ausführliche,aber wahrscheinlich rasch veraltete Installati-ons- und Einrichtungsanweisungen anzubie-ten. Schlagen Sie diese bitte in den aufgeführ-ten Informationsquellen nach. Üblicherweisesollten Sie zunächst den Compiler und dann

Laufzeit und Klassenbibliothek installierenbzw. kompilieren. Sie müssen damit rechnen,dass die Einrichtung einer lauffähigen Objec-tive-C-Entwicklungsplattform, die moderneObjective-C-Spracheigenschaften unterstützt,auf anderen System als Mac OS X aufwendigund nicht immer ganz unkompliziert ist.

Welche der in diesem Buch beschriebenen Sprach-Features unter-stützt werden, ist gleichermaßen von Compiler, Laufzeitumgebungund Klassenbibliothek abhängig. Die jeweiligen Abschnitte ver-suchen, einen groben Überblick darüber zu bieten, auf welcheFeatures Sie jeweils verzichten müssen.

| 195

Page 204: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 204/224

CompilerDie beiden gängigsten Compiler, die Objective-C-Code kompilieren

können, sind GCC (die GNU Compiler Collection) und Clang.

GCC

GCC kann Objective-C-Code kompilieren und bringt eine eigeneObjective-C-Laufzeitumgebung mit. GCC versteht allerdings nurTeile der Objective-C-Syntax, die in diesem Buch verwendet wurde.

GCC beherrscht einige Elemente von Objective-C 2.0 wie beispiels-weise Eigenschaften und schnelle Enumerationen sowie die  @try/@catch/@finally-Ausnahmeverarbeitung. Neuere Sprachformenwerden jedoch auch von den jüngsten GCC-Versionen (4.7) nochnicht unterstützt. Es gibt keine automatische Eigenschaftssyntheti-sierung. Es gibt keine Objektliterale. Und vor allem gibt es keineautomatische Speicherverwaltung (ARC). Der in diesem Buch ver-

wendete Beispielcode wird sich unter GCC nur in den seltenstenFällen (wenn überhaupt) kompilieren lassen.

GCC ist von Haus aus Teil der meisten Linux-Installationen undkann, sollte das nicht der Fall sein, in der Regel unproblematisch überdas Softwareverwaltungssystem der Distribution installiert werden.Unter Windows kann GCC mithilfe der Cygwin- oder MinGW-Pro-

 jekte (http://www.cygwin.com bzw. http://www.mingw.org ) installiert

und betrieben werden

Clang/LLVMClang (http://clang.llvm.org ) ist ein ursprünglich von Apple ent-wickeltes und dann als Open Source-Projekt weitergeführtesFrontend für den LLVM-Compiler für die Sprachen C, C++ undObjective-C. Viele der neuen Features von Objective-C, insbeson-dere ARC, wurden von Apple auf Basis der Möglichkeiten auf-gebaut, die die Clang-Infrastruktur bietet. Clang ist ausgesprochenmodular und kann Informationen zu den verschiedenen Stufen desKompilationsprozesses bieten. Clang wird z. B. intern von Xcode

196 | Kapitel 18: Alternative Plattformen

Page 205: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 205/224

für die Syntaxprüfung, für Fehlermeldungen und die Codevervoll-ständigung genutzt.

Welche der in diesem Buch vorgestellten compilerabhängigen

Features von Clang unterstützt werden, ist nur von der auf IhremSystem verfügbaren Version abhängig. Clang kann üblicherweisein einer meist nicht mehr ganz aktuellen Version aus den Software-archiven von Linux-Distributionen installiert werden. Auf derLLVM-Website unter   http://llvm.org/releases/download.html   ste-hen Binärpakete für aktuellere Versionen für verschiedene Platt-formen bereit (unter anderem auch ein, aktuell nur experimentel-

les, MinGW-basiertes Paket für Windows). Den Code für dieaktuelle Version finden Sie im LLVM-Subversion-Repository unterhttp://llvm.org/svn/llvm-project/llvm/trunk. Eine Anleitung für denDownload und die Kompilation von LLVM und Clang finden Sieunter http://clang.llvm.org/get_started.html#build .

Wenn Sie Clang aus den Quellen kompilieren

wollen, benötigen Sie natürlich zuvor einen an-deren Compiler. Dazu können Sie entweder gccoder ein clang-Binärpaket nutzen.

Laufzeitumgebungen und Plattformen

Neben Apples Laufzeitumgebung gibt es verschiedene andere Lauf-zeitumgebungen und Plattformen (Klassenbibliotheken), die unab-hängig vom Compiler eingesetzt werden können. Wir behandelnhier beides gemeinsam, weil mittlerweile die meisten Plattformenihre eigenen Laufzeitbibliotheken mitbringen.

GNU-Runtime

Die GNU-Runtime ist die Objective-C-Laufzeitumgebung, die Teilvon GCC ist. Seit GCC 4.6 unterstützt die GNU-Runtime eineReihe von Erweiterungen aus Objective-C 2.0. Neue Spracherwei-terungen wie ARC haben auch in neueren Versionen (GCC 4.7)noch keinen Eingang gefunden.

Laufzeitumgebungen und Plattformen | 197

Page 206: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 206/224

Die GNU-Runtime bringt keine Klassenbibliothek mit, sondernbietet nur eine Handvoll Klassen an, die erforderlich sind, umelementare Sprachstrukturen wie Klassen und Protokolle zu model-

lieren. Wenn Sie die GNU-Runtime nutzen wollen, werden Sie inder Regel also zusätzlich eine der nachfolgend aufgeführten alterna-tiven Plattformen einsetzen müssen. Beachten Sie, dass die GNU-Runtime eine Basisklasse mit einem anderen Namen als ApplesLaufzeitumgebung nutzt, Object statt NSObject.

GNUStep-Runtime

GNUStep (http://www.gnustep.org ) ist eine freie Implementierungder OpenStep-Spezifikation, auf die auch Apples Cocoa zurückgeht.Das GNUStep-Projekt bietet unter anderem eine Objective-C-Lauf-zeitumgebung und eine Objective-C-Klassenbibliothek. Laufzeit-umgebung und Klassenbibliothek streben nach weitestgehenderKompatibilität mit Apples Laufzeitumgebung bzw. Klassenbiblio-

thek.Die GNUStep-Runtime unterstützt unter anderem Blocks, syntheti-sierte Zugriffsmethoden für Eigenschaften und ARC. Die GNUStep-Runtime kann bei der Kompilation mit Clang mit dem Compiler-schalter -fobjc-runtime=gnustep angegeben werden.

Die Klassenbibliotheken bieten eine weitgehende Unterstützung der

Foundation- und App-Kit-APIs. Das bedeutet, mit GNUStep kön-nen auch GUI-Anwendungen erstellt werden. Eine Einschränkungist aktuell unter anderem, dass die Klassenbibliothek keine Unter-stützungsmethoden für die Objektindizierung bietet.

GNUStep ist für verschiedene Unix-Spielarten, unter anderemMac OS X, Linux und FreeBSD, sowie Windows verfügbar. Beivielen Unix-Spielarten kann es über das jeweilige Paketverwal-

tungssystem installiert werden. Download-Pakete für Unix-Sys-teme finden Sie unter   http://wwwmain.gnustep.org/resources/ downloads.php. Download-Pakete und Anleitungen für dieWindows-Installation gibt es unter http://www.gnustep.org/experi-ence/Windows.html. Für die Entwicklung von Kommandozeilen-Anweisungen reichen in der Regel die »Make«- und »Base«-Pakete(bzw. ihre distributionsspezifischen Entsprechungen, wenn Sie das

198 | Kapitel 18: Alternative Plattformen

Page 207: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 207/224

Softwarearchiv Ihrer Distribution nutzen). Beachten Sie die Listeder Abhängigkeiten unter  http://wwwmain.gnustep.org/resources/ downloads.php#pre.

Die GNUStep-Runtime kann ebenfalls aus dem Softwarearchiv(libobjc2) installiert oder aus den Quellen kompiliert werden. DenQuellcode können Sie sich folgendermaßen aus dem Subversion-Repository beschaffen:

svn co http://svn.gna.org/svn/gnustep/libs/libobjc2/trunk \libobjc2

Zur Kompilation von GNUStep-basierten Anwendungen sollten Siedie GNUStep-Infrastruktur nutzen, d. h. GNUmakefiles oder dasgnustep-config-Hilfsprogramm.

Cocotron

Cocotron (http://www.cocotron.org ) ist ein Open Source-Projekt, des-

sen Ziel der Aufbau einer plattformübergreifenden Objective-C-APIist, die weitestgehend mit Apples Cocoa-Plattform kompatibel ist.Cocotron bietet eine eigene Laufzeitumgebung und Klassenbiblio-theken, die unter anderem die AppKit- und Foundation-Funktionali-täten abdecken. Daneben pflegt das Projekt die Cocotron DeveloperTools, die eine Zusammenstellung diverser Open Source-Werkzeugezum Aufbau einer Objective-C-Entwicklungsumgebung sind.

Cocotron unterscheidet sich von GNUStep in der Hinsicht, dass esweniger für die Entwicklung auf verschiedenen Plattformen gedachtist als als Cross-Kompilationswerkzeug, mit dem unter Mac OS X Objective-C-basierte Anwendungen für andere Plattformen erstelltwerden können, insbesondere moderne Windows-Systeme. WennSie unter Linux oder Windows entwickeln wollen, ist GNUStepdeswegen wahrscheinlich die bessere Wahl. Ein Problem bei Coco-tron ist, dass der Kompilationsprozess von Haus aus immer nochGCC-basiert ist und deswegen keine ARC-Unterstützung bietet.

ObjFW

ObjFW (https://webkeks.org/objfw/ ) ist ein leichtgewichtiges, platt-formunabhängiges Objective-C-Framework, das ein anderes Kon-

Laufzeitumgebungen und Plattformen | 199

Page 208: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 208/224

Page 209: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 209/224

Page 210: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 210/224

-fblocks-runtime-optional

Die Blocks-Runtime schwach einbinden.

-fblocks

Aktiviert Blocks.

-fconst-strings

Bewirkt, dass für Stringliterale ein mit  const qualifizierter Typverwendet wird.

-fconstant-string-class Klassenname

Gibt den Namen der Klasse an, die für unveränderliche Objecti-

ve-C-Stringobjekte verwendet werden soll.

-fno-const-strings

In C und Objective-C keinen mit  const  qualifizierten Typ fürStringliterale verwenden.

-fno-constant-cfstrings

Keine CoreFoundation-Stringkonstanten erstellen.

-fno-objc-arc

Schaltet ARC bei Projekten, die standardmäßig ARC nutzen, fürdie Kompilation einzelner Dateien aus.

-fno-objc-infer-related-result-type

Den Objective-C-Rückgabetyp nicht aus der Methodenfamilieableiten.

-fobjc-arc-exceptions

Aktiviert ausnahmeverarbeitungssicheren Code unter ARC.

-fobjc-arc

Aktiviert ARC.

-fobjc-default-synthesize-properties

Aktiviert die automatische Synthetisierung von Eigenschaften.-fobjc-dispatch-method=Wert

Gibt die zu verwendende Art der Methodenauflösung an.

-fobjc-exceptions

Aktiviert die Objective-C-Ausnahmen.

202 | Kapitel 19: Clang-Optionen

Page 211: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 211/224

-fobjc-fragile-abi

Aktiviert die Verwendung der veralteten fragilen ABI.

-fobjc-gc-only

Für die Objective-C-Speicherverwaltung ausschließlich die Gar-bage Collection verwenden.

-fobjc-gc

Aktiviert die Objective-C-Garbage-Collection.

-fobjc-runtime=Wert

Generiert Ausgaben, die mit der entsprechenden Laufzeit-

umgebung kompatibel sind. Unterstützte Werte sind   macosx,macosx-fragile, ios, gcc gnustep und  objfw.

-fobjc-runtime-has-arc

Versichert, dass die anvisierte Objective-C-LaufzeitumgebungARC-Einstiegspunkte bietet.

-fobjc-runtime-has-terminate

Versichert, dass die anvisierte Objective-C-Laufzeitumgebungeinen objc_terminate-Einstiegspunkt bietet.

-fobjc-runtime-has-weak

Versichert, dass die anvisierte Objective-C-Laufzeitumgebungschwache Referenzen unterstützt.

Clang-Optionen | 203

Page 212: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 212/224

Page 213: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 213/224

Index

Symbole

#import-Präprozessordirektive 6,8

%@-Stringformatangabe 6&-Adressoperator 24*-Dereferenzierungsoperator 24*-Zeigerindikator 24+, Klassennachrichtdeklaration 39-, Instanznachrichtdeklaration 39

.-Operator, Eigenschaftszugriff  28

..., Varargs-Parameter 46

.h-Dateinamenserweiterung 8==-Operator 29@"...", Stringliterale 6, 15@[]-Arrayliterale 15@{...}-Dictionaryliterale 16

A+accessInstanceVariablesDirect-

ly:-Nachricht 173Adressoperator, & 24+alloc-Nachricht 27, 88, 173

Objekte besitzen 111-alloc-Nachricht 89Allozierung von Objekten 88 –89

alternative Plattformen 195-fobjc-runtime-Compilerschal-

ter 203ARC 104 –105

-fobjc-arc-Compilerschalter202

Ausnahmen unter 79Blocks 169

Eigenschaftsattribute unter

106Regeln 109strong-Eigenschaftsattribut

106unbekannte Selektoren 128Variablenqualifizierer 107weak-Eigenschaftsattribut 106

+archiveDataWithRootOb-

 ject:-Nachricht 156+archiveRootObject:toFile:-Nach-richt 156

Archivierung von Objekten 151Coder-Objekte 156

Archivierungsmethoden 154Array-ähnlicher Zugriff auf Ob-

 jekte 30

ArrayobjekteLiterale 15assign-Eigenschaftsattribut 56Aufrufen von Methoden 45Auslösen von Ausnahmen 80Ausnahmen 78

-fobjc-arc-exceptions-Compi-lerschalter 202

-fobjc-exceptions-Compiler-schalter 202auslösen 80, 83Handler 80Handler für nicht abgefangene

82NSException-Objekt erstellen

83

| 205

Page 214: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 214/224

Objekte 80Probleme unter ARC 79vs. Fehler 73

Auto-Release-Blöcke 108

Auto-Release-PoolsMRC 114Objekte übergeben an 112

automatische Synthetisierung vonEigenschaften 50

-autorelease-Nachricht 110-autorelease-Nachricht 174@autoreleasepool-Compilerdirek-

tive 14, 108, 185vs. NSAutoreleasePool-Ob-

 jekte 114 _ _autoreleasing-Variablenqualifi-

zierer 108@autoreleaspool-Compilerdirek-

tive 6

BBesitzen von Objekten 111 _ _block-Variablenqualifizierer

108, 167Block_copy()-Makro 172Block_release()-Makro 172Blocks 18, 159

-fblocks-Compilerschalter 202

als Closures 168als Objekte 161Blocktyp deklarieren 160Blockvariablen 167Definition 159dynamische Nachrichtenimple-

mentierung stellen 138globale vs. kontextgebundene

168kontextgebundene 169kopieren 171Objekte manipulieren 166Rückgabetyp explizit angeben

160Speicherort von Blockvariablen

168

Typumwandlung 161Variablen einfangen 165zirkuläre Referenzen 164

Boxed Expressions 18

CC-Datentypen

Unterstützung in Objective-C11

C-Funktionenself als erstes Argument 131

C-Zeiger 23, 96

Funktionszeiger casten 135Objekte referenzieren 11referenzierten Wert abrufen 24Typumwandlung 61und Polymorphie 60Zeiger auf Zeiger 25Zeiger auf Zeiger, Beispiel 74

Cachen von Implementierungen

135Callstack 83-callStackReturnAddresses-Nach-

richt (NSException) 83-callStackSymbols-Nachricht

(NSException) 83Casts

Blocks 161

@catch-Compilerdirektive 79,186

Clang 196Optionen 201

clang-Compiler 8+class-Nachricht 118, 174-class-Nachricht 174@class-Compilerdirektive 186

-class-Nachricht 118Class-Objekte 117Class-Typ 25

Objektreferenzen 118class_addMethod()-Funktion 137class_getName()-Funktion 120-className-Nachricht 120Closures 168

206 | Index

Page 215: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 215/224

 _cmd-Argument 131Cocotron 199-code-Nachricht (NSError) 76Code

auf der Kommandozeile kom-pilieren 8

mit XCode schreiben undkompilieren 7

Coder-Objekte 152, 156Beispiel 157prüfen 155

Collection-Typen

Objekte enumerieren 30Unveränderlichkeit 31

@compatibility_alias-Compilerdi-rektive 187

CompilerARC 104Erkennung falscher Typanga-

ben 41

Fehler/Warnung bei unbe-kannten Selektoren 128Nachrichtenprüfung 128unbekannte Selektoren 132

Compilerdirektiven 13@autoreleasepool 6, 14,

185 –186@catch() 79

@class 186@compatibility_alias 187@dynamic 187@encode() 188@end 188@finally 188@implementation 188@interface 33, 188

@optional 68, 189@package 36, 189@private 36, 190@property 49, 190@protected 36, 190@protocol 67, 191@public 36@required 68, 191

@selector 192@selector() 130@synthesize 50, 192@throw 79, 192

@try 79, 193+conformsToProtocol:-Nachricht

124, 174-conformsToProtocol:-Nachricht

124-conformsToProtocol:-Nachricht

174-copy-Nachricht 96

+copyWithZone:-Nachricht 174copy-Eigenschaftsattribut 56-copy-Nachricht 174

NSString-Klasse 99Objekte besitzen 111

-copyWithZone:-Nachricht 96implementieren 98

D-dealloc-Nachricht 99, 175Dereferenzierungsoperator, * 24-description-Nachricht 116, 175designierte Initialisierer 90

Aufgaben 92delegieren an, in -init-Metho-

den 93

DictionariesLiterale 16

-dictionaryWithValuesFor-Keys:-Nachricht 175

-domain-Nachricht (NSError) 76Downcast 61@dynamic-Compilerdirektive 52,

187

dynamische Implementierung vonEigenschaften 52

dynamische Nachrichtenauflö-sung 45

dynamische Operationenid-Typ 26

dynamische ReferenzenEigenschaftszugriff  29

Index | 207

Page 216: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 216/224

EEigenschaften 47

@property-Compilerdirektive49

Attribute 54Deklaration 49dynamisch implementieren 52in Kategorien 63in privaten Klassenerweiterun-

gen 65manuelle Implementierung 48,

51

nicht-atomare 52private definieren 65Speicherverwaltung 55Synthetisierung 50Zugriff auf  28, 52, 55

Empfänger 12Typ in Nachrichtendeklaration

angeben 39

-encodeWithCoder:-Nachricht 152@end-Compilerdirektive 188-enumerateObjectsUsingBlock-

Nachricht 30+errorWithDomain:code:userIn-

fo:-Nachricht (NSError) 77Erstellen von Objekten 87+exceptionWithName:rea-

son:userInfo:-Nachricht(NSException) 83

Exceptions siehe Ausnahmen;Fehler

explizite Synthesierung von Eigen-schaften 51

F

F-Postfix, Zahlliterale 17-fblocks-Compilerschalter 202-fconstant-string-class-Compiler-

schalter 15, 202Fehler 74

Beschreibung 77Code 75 –76

Domain 76in -init-Methoden 94unbekannte Selektoren 128vs. Ausnahmen 73

Felder 28, 35in Kategorien 63in privaten Klassenerweiterun-

gen 65Kapselung umgehen mit Key/

Value-Coding 144Sichtbarkeit 36statische 37

synthetisierte Hintergrundfel-der 51

Werte über Schlüssel/Wert-Be-ziehungen abrufen 143

Zugriff  37Zugriff auf, in Blocks 163

Feldzugriff ->-Operator 37

->-Operator, Feldzugriff  28Feldzugriff  28@finally-Compilerdirektive 79,

188-finishDecoding-Nachricht 157-finishEncoding-Nachricht 157-fobjc-arc-Compilerschalter 8, 202-fobjc-runtime-Compilerschalter

203-fobjc-exceptions-Compilerschal-ter 202

-fobjc-arc-exceptions-Compiler-schalter 202

-forwardingTargetForSe-lector:-Nachricht 139, 175

-forwardInvocation:-Nachricht

139 –140, 175Foundation-FunktionenNSLog() 6

Foundation.h-Header 9-framework-Compilerschalter 8Frameworks 9Freigeben von Objekten 112

208 | Index

Page 217: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 217/224

FunktionenC-Funktion für Implementie-

rung speichern 137Funktionszeiger casten 135

vs. Blocks 18

GGCC (GNU Compiler Collection)

196Getter, Namenskonvention 48getter-Eigenschaftsattribut 55globale Blocks 168

GNU-Runtime 197GNUStep 198

HHandler für Ausnahmen 80-hash-Nachricht 116, 176Headerdateien 8

anwendungsspezifischeHeader 9

Framework-Header importie-ren 9

importieren 6, 8NSKeyValueCoding.h-Header

143objc/runtime.h-Header 115Protokoll-Header importieren

70System-Header 9Umbrella-Header 9

Heap 101-helpAnchor-Nachricht (NSError)

77Hintergrundfelder von Eigen-

schaftenabweichende Namen bei auto-

matischer und expliziterSynthetisierung 51

deklarieren 48Synthetisierung steuern 50

Iid-Typ 11, 25

Klassenobjekte 118IMP-Typ 130

imp_implementationWithBlock()-Funktion 138

@implementation-Compilerdirek-tive 33, 188

Implementierungen 130auf konkreten Funktionszei-

gertyp casten 131cachen 135

dynamisch mit einem Block-Objekt stellen 138

dynamisch stellen 137Nachrichten 41Protokolle 69Schnittstelle importieren 35

Importieren von Headerdateien 6informelle Protokolle 71

-init-Methodendesignierte Initialisierer 90designierten Initialisierer auf-

rufen 93Fehler in 94Typ von self  43Unterschied zu Konstruktoren

90

-init-Nachricht 27, 88, 176-initForReadingWithData:-Nach-

richt 157-initForWritingWithMutableDa-

ta:-Nachricht 157Initialierungsmethoden

mit Parametern 27Initialisierungsstruktur für Klassen

94+initialize-Nachricht 94, 176-initWithCoder:-Nachricht 152-initWithDomain:do-

main:code:userInfo:-Nachricht(NSError) 77

-initWithFormat:-Nachricht(NSString) 27

Index | 209

Page 218: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 218/224

Page 219: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 219/224

Kontext, Blocks 161kontextgebundene Blocks 169Kopien von Objekten 95

tiefe und flache Kopien 98

KVC-Konformität 143KVC-Validierung 147

LL-Postfix, Zahlliterale 17Laufzeit

Eigenschaftsimplementierungstellen 52

Laufzeitinformationen 115Laufzeitumgebung

alternative 197Funktionsinformationen 123Informationen zu Objekten

116Klasseninformationen 117Protokollinformationen 124

Literale 14Arrays 15Blocks 159Dictionaries 16String 6Stringobjekte 15Zahlen 16

LLVM 196

+load-Nachricht 178-localizedDescription-Nachricht

(NSError) 77-localizedFailureReason-Nach-

richt (NSError) 77-localizedRecoveryOptions-Nach-

richt (NSError) 77-localizedRecoverySuggestion-

Nachricht (NSError) 78

MMac OS X 

Auto-Release-Pools unter 109Speicherverwaltung unter 102

main()-Funktion 5

manuelle Implementierung vonEigenschaften 51

Messaging 127Metaklassen 119

Klassenobjekte erkennen 122Objekt abrufen 119

Methodenaufrufen 45vs. Nachrichten 13siehe auch Nachrichten 38

Methodenfamilien 41Methodenüberladung vs. Metho-

denfamilien 41-methodForSelector:-Nachricht

135, 178-methodSignatureForSe-

lector:-Nachricht 133, 141,178

Monkey-Patching 63MRC 110

Auto-Release-Pools 114Blocks 170unbekannte Selektoren 129

-mutable...Value...For...-Nach-richten 179

+mutableCopyWithZone:-Nach-richt 96, 180

-mutableCopy-Nachricht 96, 111,

179

NNachrichten 12

+alloc 27+new 27-enumerateObjectUsindBlock

30

-init 27-initWithFormat: 27-isEqual: 30-isEqualToString: 30an aktuelle Instanz senden 42an Oberklasse senden 59definieren 45deklarieren 39

Index | 211

Page 220: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 220/224

dynamisch ausführen 131, 134dynamisch ausführen mit

NSInvocation-Objekt 132Implementierung 41

Implementierung dynamischstellen 137

Implementierungen cachen135

in Kategorien überschreiben 64in Protokollen deklarieren 67Klassenname als Empfänger 118mit einer variablen Anzahl an

Parametern 46mit NSInvocation-Objekt kap-

seln 140mit Parametern 40Name 39ohne Parameter 40optionale, aufrufen 70optionale, in Protokollen 68

Parameter 39Parameter angeben 12private definieren 65Prüfung durch Compiler 128Rückgabetyp deklarieren 39schachteln 13self-Empfänger 42senden 45, 127

Sichtbarkeit 38Syntax 28unterstützte prüfen 124vs. Methoden 13Weiterleitung 139

nachträgliche Erweiterung vonKlassen 63

-name-Nachricht (NSException)

83NamensbereicheKategorien 63

Namensbereiche für Instanzvaria-blen und Nachrichten 46

NamenskonventionenGetter 48Kategoriedateien 64

Setter 48Speicherverwaltung 111

+new-Nachricht 27, 89, 180Objekte besitzen 111

nicht abgefangene Ausnahmen,Handler für 82

nil-terminierte Listen 47nil-Wert

aus Initialisierer zurückliefern,um Fehler anzuzeigen 94

nonatomic-Eigenschaftsattribut52, 56

NSArray-Klasse 15Objektindizierung 31

NSAutoreleasePool-Klasse 114NSClassFromString()-Funktion

120NSCoding-Protokoll 151

implementieren 153NSCopying-Protokoll 97

Dictionaryschlüssel und 16implementieren 97NSCopyObject()-Funktion 99NSDictionary-Klasse 16

Klassenobjekte als Schlüssel119

Objektindizierung 31NSError

Warndialog 76NSError-Klasse 74Instanzen erstellen 75Nachrichten 76Objekte erstellen 77

NSException-KlasseNachrichten 83und andere Ausnahmeobjekte

80NSFastEnumeration-Protokoll 30NSInvocation-Klasse 132

Argument von -forwardInvo-cation:-Nachricht 140

Objekte ausführen 141NSKeyedArchiver-Klasse 154

Nachrichten 156

212 | Index

Page 221: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 221/224

NSKeyedUnarchiver-Klasse 154Nachrichten 157

NSKeyValueCoding-Protokoll 143NSLog()-Funktion 6

NSMethodSignature-Klasse 133NSMutableCopying-Protokoll 97NSNumber-Klasse 16

Tagged Pointer und 17NSObject-Klasse 85

Instanzmethoden durch Klas-senmethoden verdecken118

Klassenobjekte 118Laufzeitinformationen 115

NSObject-Protokoll 69, 115NSSelectorFromString()-Funktion

130NSSet-Klasse

Objektindizierung 31NSSetUncaughtExceptionHand-

ler()-Funktion 82NSString-KlasseVerhalten von -copy-Nachricht

99NSStringFromClass()-Funktion

120

O

OberklasseInitialisierer aufrufen 92Nachrichten senden an 59Schnittstelle in Unterklassen-

deklaration einschließen 34objc/runtime.h-Header 115objc_getClass()-Funktion 120objc_lookUpClass()-Funktion 120

objc_msgSend()-Funktion 134object_getClass()-Funktion 119Objective-C-Laufzeitumgebung

115Objective-C-Stringliterale 6Objekte 23, 87

archivieren 151

Ausnahmeobjekte 80besitzen von 111Blocks als 161downcast 61

Eigenschaftszugriff  28enumerieren 30erstellen 11, 27Felder 28Feldzugriff  28freigeben 112indizieren 30Ivarwerte über Schlüssel/Wert-

Beziehungen abrufen 143Klassenobjekte 117kopieren 95Literaldeklarationen 14manipulieren in Blocks 166mit Laufzeittyp erstellen 45referenzieren 11schlüsselbasierte Interaktion

mit 144umwandeln in Strings 116unterstützte Nachrichten prü-

fen 124Upcast 61Variablen deklarieren 23vergleichen 29, 117vernichten 99

Weiterleitungsobjekt stellen139ObjFW 199Operatoren

&-Adressoperator 24*-Dereferenzierungsoperator

24==-Vergleichsoperator 29

->-Operator 37Feldzugriff  28@optional-Compilerdirektive 68,

189optionale Nachrichten aufrufen 70optionale Protokollnachrichten 68

Index | 213

Page 222: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 222/224

P@package-Compilerdirektive 36,

189Parameter 12

deklarieren 40für Ausnahmeverarbeitung 80Nachrichten 39Nachrichten mit variabler An-

zahl 46von Schnittstelle abweichender

Typ in Implementierung 41-performSelector-Nachrichten

131, 180Polymorphie 56

in Objective-C 60Protokolltyp 71

@private-Compilerdirektive 36,190

Properties siehe Eigenschaften@property-Compilerdirektive 49,

190@protected-Compilerdirektive

36, 190@protocol-Compilerdirektive 67,

191Protokolle 67

als Einschränkung auf Varia-blentyp 71

informelle 71übernehmen 69

@public-Compilerdirektive 36Punktnotation 28, 52

R+raise:...-Nachrichten (NSExcep-

tion) 83

-raise-Nachricht (NSException)84

readonly-Eigenschaftsattribut 55readwrite-Eigenschaftsattribut 55-reason-Nachricht (NSException)

84-recoveryAttempter-Nachricht

(NSError) 78

Reference Counting siehe Spei-cherverwaltung

ReferenzparameterNSError-Referenz 74

Referenzzyklen durchbrechen 107-release-Nachricht 110, 180@required-Compilerdirektive 68,

191+resolveClassMethod:-Nachricht

137, 181+resolveInstanceMethod:-Nach-

richt 137, 181

-respondsToSelector:-Nachricht70, 123, 181Beispiel 139

retain-Eigenschaftsattribut 56-retain-Nachricht 110, 181-retainCount-Nachricht 110-retainCount-Nachricht 182Rückgabetyp

Blocks 159von Blocks explizit angeben 160von Schnittstelle abweichender

in Implementierung 41

SSchachteln von Nachrichten 13Schlüssel/Wert-Beziehungen 143

virtuelle Schlüssel 146schlüsselbasierte Archive 154

Archivierungsmethoden 154vs. sequentielle Archive 153

Schlüsselpfade 145Schlüsselpfadoperatoren 148schnelle Enumeration 30Schnittstellen

in Implementierungsdatei im-portieren 35

siehe auch Klassen 34schwache Referenzen 105

Referenzen durchbrechen 107von Nachrichten deklarieren

39SEL-Typ 130

214 | Index

Page 223: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 223/224

Page 224: 3868993738 Objective

8/13/2019 3868993738 Objective

http://slidepdf.com/reader/full/3868993738-objective 224/224

TypumwandlungenBlocks 161Funktionszeiger casten 131,

135

UU-Postfix, Zahlliterale 17Übernahme von Protokollen 69Überschreiben von Nachrichten in

Kategorien 64Umbrella-Header 9+unarchiveObjectWith-

l h h 1

Variablenqualifizierer _ _block 167ARC 107

Vererbung 56

Felder 37Protokolle 68

Vergleichen von Objekten 29, 117Verhalten vom Klassentyp abhän-

gig machen 121Vernichten von Objekten 99virtuelle Schlüsselbeziehungen

146

d kl