Discover millions of ebooks, audiobooks, and so much more with a free trial

Only $11.99/month after trial. Cancel anytime.

Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung
Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung
Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung
Ebook553 pages4 hours

Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung

Rating: 0 out of 5 stars

()

Read preview

About this ebook

Dieses Buch hilft Ihnen, die Möglichkeiten von Objective-C auszureizen. Schreiben Sie außergewöhnlichen Code für OS X und iOS, der leicht verständlich und einfach zu warten ist. In einem kompakten, an praktischen Beispielen orientierten Stil stellt Matt Galloway 52 empfehlenswerte Vorgehensweisen sowie aus dem Programmiererleben gegriffene Codebeispiele zum Thema Objective-C vor, die Sie sonst nirgendwo finden können. Dabei beschränkt sich Galloway nicht nur auf die Kernelemente der Sprache. Sie lernen, wichtige Klassen aus dem Foundation-Framework sowie aus modernen Systembibliotheken wie Grand Central Dispatch einzubeziehen und zu nutzen.

• Interaktionen und Beziehungen zwischen Objective-C-Klassen optimieren
• Interface- und API-Design meistern
• Wartungsfreundlichen und fehlerresistenten Code schreiben
• Speicherlecks vermeiden
• Arrays, Dictionaries und Sets effektiv einsetzen
LanguageDeutsch
PublisherSmartBooks
Release dateMar 5, 2014
ISBN9783944165721
Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung

Related to Effektiv Objective-C 2.0 programmieren

Related ebooks

Programming For You

View More

Related articles

Reviews for Effektiv Objective-C 2.0 programmieren

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    Effektiv Objective-C 2.0 programmieren - Matt Galloway

    Vorwort

    Objective-C ist weitschweifig. Objective-C ist plump. Objective-C ist hässlich. All diese Meinungen über Objective-C habe ich schon gehört. Ich dagegen empfinde die Sprache als elegant, flexibel und schön. Damit sie so sein kann, müssen Sie allerdings nicht nur die Grundlagen, sondern auch die Eigenheiten, Fallstricke und Feinheiten kennen, und darum geht es in diesem Buch.

    Über dieses Buch

    Die Syntax von Objective-C können Sie mit diesem Buch nicht lernen. Es wird vorausgesetzt, dass Sie sie bereits kennen. Stattdessen soll Ihnen dieses Buch beibringen, wie Sie das ganze Potenzial der Sprache ausschöpfen, um guten Code zu schreiben. Objective-C ist dank seiner Wurzeln in Smalltalk außerordentlich dynamisch. Ein Großteil der Arbeit, die in anderen Sprachen gewöhnlich der Compiler ausführt, wird in Objective-C von der Laufzeitkomponente erledigt. Das kann dazu führen, dass Code beim Testen hervorragend funktioniert, in der Produktion aber auf seltsame Weise fehlschlägt, etwa bei der Verarbeitung ungültiger Daten. Die beste Lösung zur Vermeidung solcher Probleme besteht natürlich darin, guten Code zu schreiben.

    In vielen der Themen dieses Buches geht es streng genommen nicht um Objective-C im engeren Sinne, sondern um Einrichtungen aus den Systembibliotheken, z. B. um Grand Central Dispatch aus libdispatch. Es werden auch viele Klassen aus dem Foundation-Framework behandelt, nicht zuletzt auch die Wurzelklasse NSObject, da moderne Objective-C-Programmierung gewöhnlich für die Plattformen OS X und iOS eingesetzt wird. Bei der Entwicklung für diese Betriebssysteme werden Sie zweifellos die System-Frameworks Cocoa bzw. Cocoa Touch verwenden.

    Seit dem Aufkommen von iOS haben sich Scharen von Entwicklern auf die Programmierung in Objective-C gestürzt. Manche dieser Entwickler sind sind Neulinge, andere kommen von Java oder C++, wieder andere aus der Webentwicklung. Zu welcher Gruppe Sie auch immer gehören mögen, nehmen Sie sich die Zeit, die Sprache effektiv zu lernen. Dadurch können Sie Code schreiben, der effizienter ist, sich leichter warten lässt und weniger Fehler enthält.

    Ich habe nur etwa sechs Monate gebraucht, um dieses Buch zu schreiben, aber Jahre der Erfahrung sind darin eingeflossen. Aus einer Laune heraus hatte ich einen iPod touch gekauft, und als das erste SDK veröffentlicht wurde, ent-schloss ich mich, ein wenig mit der Entwicklung herumzuspielen. Das führte dazu, dass ich meine erste »App« schrieb, die ich unter dem Namen Subnet Calc veröffentlichte und die weit häufiger heruntergeladen wurde, als ich mir ausgemalt hatte. Damit stand für mich fest, dass meine Zukunft in dieser wunderschönen Sprache lag, die ich neu kennengelernt hatte. Seit diesem Zeitpunkt erforsche ich Objective-C und führe auf meiner Website www.galloway.me.uk/ ein Blog darüber. Am meisten interessieren mich die internen Mechanismen, z. B. die Funktionsweise von Blöcken und ARC. Als ich die Gelegenheit erhielt, ein Buch über diese Sprache zu schreiben, ergriff ich meine Chance.

    Um die Möglichkeiten dieses Buches ganz auszuschöpfen, sollten Sie darin herumstöbern und sich die Themen herauspicken, die für Sie besonders interessant sind oder die Aufgaben betreffen, an denen Sie gerade arbeiten. Alle Themen können unabhängig voneinander gelesen werden, wobei Querverweise zu verwandten Themen führen. In den einzelnen Kapiteln sind jeweils ähnliche Themen zusammengefasst, weshalb Sie sich an den Kapitelüberschriften orientieren können, um die Themen zu bestimmten Sprachmerkmalen zu finden.

    Zielgruppe

    Dieses Buch richtet sich an Entwickler, die ihre Kenntnisse in Objective-C vertiefen und Code schreiben möchten, der wartungsfreundlich und effizient ist und weniger Fehler enthält. Auch wenn Sie noch kein Objective-C-Entwickler sind, aber einen Hintergrund in anderen objektorientierten Sprachen wie Java oder C++ haben, können Sie hier etwas lernen. In diesem Fall ist es jedoch klug, sich zunächst eingehender mit der Syntax von Objective-C zu beschäftigen.

    Der Inhalt dieses Buches

    Dieses Buch dient nicht dazu, Ihnen die Grundlagen von Objective-C beizubringen, die Sie aus vielen anderen Büchern und Quellen lernen können. Stattdessen geht es darum, wie Sie diese Sprache effektiv einsetzen. Das Buch ist in Themen mit einer gut verdaulichen Menge an Informationen gegliedert, und diese Themen wiederum sind logisch zu Kapiteln geordnet:

    Kapitel 1: Machen Sie sich mit Objective-C vertraut

    Hier lernen Sie die wichtigsten allgemeinen Prinzipien der Sprache kennen.

    Kapitel 2: Objekte, Nachrichten und die Laufzeit

    Das Thema dieses Kapitels sind die Beziehungen und Wechselwirkungen zwischen den Objekten, die ein wichtiges Merkmal jeder objektorientierten Sprache bilden. Außerdem wird die Laufzeitkomponente genauer untersucht.

    Kapitel 3: Interface- und API-Design

    Code wird selten nur für den einmaligen Gebrauch geschrieben und dann nie wieder verwendet. Selbst wenn Sie ihn nicht veröffentlichen, werden Sie Ihren Code wahrscheinlich in mehr als einem Projekt einsetzen. In diesem Kapitel erfahren Sie, wie Sie Klassen schreiben, die in Objective-C nicht fremdkörperhaft wirken.

    Kapitel 4: Protokolle und Kategorien

    Protokolle und Kategorien sind wichtige Sprachmerkmale, die Sie beherrschen müssen. Ihre effektive Nutzung macht Ihren Code leichter lesbar, wartungsfreundlicher und weniger fehleranfällig. Dieses Kapitel hilft Ihnen dabei, die Dinge zu meistern.

    Kapitel 5: Speicherverwaltung

    Das Speicherverwaltungsmodell von Objective-C nutzt Reference Counting, was für Neulinge lange Zeit eine heikle Angelegenheit war, vor allem für diejenigen, die bereits in einer Sprache mit Garbage Collector programmiert haben. Die Einführung von Automatic Reference Counting (ARC) macht die Sache einfacher, aber Sie müssen trotzdem noch auf eine Menge wichtiger Dinge achten, damit Ihr Objektmodell korrekt ist und keine Speicherlecks aufweist. Dieses Kapitel fördert Ihre Wahrnehmung für häufig vorkommende Fallstricke der Speicherverwaltung.

    Kapitel 6: Blöcke und Grand Central Dispatch

    Blöcke sind lexikalische Closures für C, die von Apple eingeführt wurden. Sie werden in Objective-C häufig verwendet, um Dinge zu erreichen, für die sonst viel repetitiver Standardcode geschrieben werden müsste, und um eine Codetrennung herbeizuführen. Grand Central Dispatch (GCD) bietet eine einfache Schnittstelle für Multithreading. Blöcke werden dabei als GCD-Aufgaben betrachtet, die je nach verfügbaren Systemressourcen auch parallel ausgeführt werden können. Die Lektüre dieses Kapitels versetzt Sie in die Lage, diese beiden wichtigen Technologien anzuwenden.

    Kapitel 7: Die System-Frameworks

    Objective-C-Code schreiben Sie gewöhnlich für OS X oder iOS. In diesen Fällen steht Ihnen mit Cocoa bzw. Cocoa Touch der komplette Vorrat an System-Frameworks zur Verfügung. Dieses Kapitel gibt einen kurzen Überblick über die Frameworks und stellt einige ihrer Klassen genauer vor.

    Wenn Sie irgendwelche Fragen, Kommentare oder Bemerkungen zu diesem Buch haben, können Sie sich gern (in englischer Sprache) an mich wenden.

    Kontaktinformationen finden Sie auf der Website zu diesem Buch auf www.effectiveobjectivec.com.

    Danksagung

    Als ich gebeten wurde, ein Buch über Objective-C zu schreiben, war ich sofort ganz aufgeregt. Ich hatte bereits andere Bücher aus dieser Reihe gelesen, weshalb es mir klar war, dass es eine Herausforderung darstellt, ein Buch dieser Art für Objective-C zu verfassen. Mit der Hilfe vieler anderer Personen konnte dieses Buch aber verwirklicht werden.

    Viele Anregungen für dieses Buch stammen aus den hervorragenden Blogs über Objective-C. Mike Ash, Matt Gallagher und »bbum« sind nur einige der Personen, deren Blogs ich lese. Sie haben mir geholfen, mit den Jahren die Sprache eingehend zu verstehen. Auch NSHipster von Matt Thompson bietet großartige Artikel, die mir Denkanstöße gegeben haben, während ich dieses Buch zusammenstellte. Auch die hervorragende Dokumentation von Apple erwies sich als äußerst nützlich.

    Ohne die ausgezeichnete Betreuung und Wissensvermittlung während meiner Arbeit für MX Telecom wäre ich nicht in der Lage gewesen, dieses Buch zu schreiben. Vor allem habe ich Matthew Hodgson zu danken, der mir die Gelegenheit gab, auf der Grundlage eines ausgereiften C++-Codestamms die erste iOS-Anwendung der Firma zu schreiben. Das Wissen, das ich in diesem Projekt gewonnen habe, bildete die Grundlage für einen Großteil meiner nachfolgenden Arbeit.

    Im Laufe der Jahre habe ich mit vielen außergewöhnlichen Kollegen zusammengearbeitet, mit denen ich später in Kontakt geblieben bin, sei es aus fachlichen Gründen oder um einfach ein Bierchen zu trinken und einen netten Schwatz zu halten. Alle haben mir dabei geholfen, dieses Buch zu schreiben.

    Mit dem Team von Pearson habe ich fantastische Erfahrungen gemacht. Trina MacDonald, Olivia Basegio, Scott Meyers und Chris Zahn haben mir Hilfe und Ermutigung geboten, wenn ich sie brauchte. Sie ermöglichten es mir, das Buch ohne Ablenkung zu schreiben, und beantworteten all meine Fragen.

    Die Fachgutachter, mit denen ich zusammenarbeiten durfte, waren außerordentlich hilfreich. Mit ihren Adleraugen haben sie den Inhalt dieses Buchs so weit verbessert, wie es nur möglich war. Sie können alle stolz auf die Genauigkeit sein, die sie bei der Untersuchung des Manuskripts an den Tag legten.

    Ohne das Verständnis und die Unterstützung von Helen hätte ich dieses Buch nicht verfassen können. Unser erstes Kind wurde an dem Tag geboren, an dem ich mit dem Schreiben beginnen sollte, weshalb ich die Aufgabe natürlich kurzzeitig aufschob. Sowohl Helen als auch Rosie waren fantastisch dabei, mich während der ganzen Zeit in Schwung zu halten.

    Kapitel 1

    Machen Sie sich mit Objective-C vertraut

    Mit einer ganz neuen Syntax erweitert Objective-C die Sprache C um objektorientierte Merkmale. Diese Syntax wird oft als weitschweifig bezeichnet, da sie eine ganze Menge eckiger Klammern umfasst und auch vor extrem langen Methodennamen nicht zurückschreckt. Der resultierende Quellcode ist zwar sehr gut lesbar, bietet aber seine Schwierigkeiten für C++- und Java-Entwickler.

    Objective-C lässt sich schnell erlernen, weist aber viele Feinheiten auf, über die Sie sich im Klaren sein müssen, und es verfügt über Merkmale, die häufig übersehen werden. Manche Merkmale werden oft missbraucht oder nicht richtig verstanden, was zu Code führt, der sich nur schwer warten oder debuggen lässt. In diesem Kapitel geht es um die Grundlagen. Die weiteren Kapitel behandeln einzelne Gebiete der Sprache und der zugehörigen Frameworks.

    Thema 1: Lernen Sie die Ursprünge von Objective-C kennen

    Objective-C ähnelt anderen objektorientierten Sprachen wie C++ und Java, weist aber auch viele Unterschiede auf. Wenn Sie bereits Erfahrungen in solchen Sprachen haben, werden Ihnen viele der verwendeten Techniken und Muster vertraut vorkommen. Die Syntax allerdings dürfte fremdartig wirken, da sie anstelle von Funktionsaufrufen eine Benachrichtigungsstruktur verwendet. Objective-C hat sich aus der Sprache Smalltalk entwickelt, aus der das Konzept der Nachrichten (messaging) bildet. Den Unterschied zwischen Nachrichten und Funktionsaufrufen können Sie im folgenden Beispiel erkennen:

    // Nachricht (Objective-C)

    Object *obj = [Object new];

    [obj performWith:parameter1 and:parameter2];

    // Funktionsaufruf (C++)

    Object *obj = new Object;

    obj->perform(parameter1, parameter2);

    Der Hauptunterschied besteht darin, dass in der Nachrichtenstruktur die Laufzeitkomponente entscheidet, welcher Code ausgeführt wird, während dies bei Funktionsaufrufen der Compiler tut. Nur wenn in dem Beispiel mit dem Funktionsaufruf ein Polymorphismus auftritt, wird zur Laufzeit in einer virtuellen Tabelle nachgeschlagen, was bei Nachrichten jedoch immer der Fall ist. Der Compiler kümmert sich nicht einmal darum, an welche Art von Objekt die Nachricht geht. Auch dies wird zur Laufzeit ermittelt, und zwar durch den Vorgang der dynamischen Bindung, die wir uns ausführlicher in Thema 11 ansehen.

    Die Hauptarbeit erledigt in Objective-C die Laufzeitkomponente und nicht der Compiler. Sie enthält alle Datenstrukturen und Funktionen, die für die objektorientierten Merkmale der Sprache erforderlich sind. Darunter fallen beispielsweise auch alle Methoden zur Speicherverwaltung. Im Grunde handelt es sich bei der Laufzeitkomponente um Code, der den von Ihnen geschriebenen Code zusammenhält. Die Komponente hat die Form einer dynamischen Bibliothek, mit der Ihr Code verlinkt ist. Daher kann Ihre Anwendung bei einer Aktualisierung der Laufzeitkomponente sofort auf die damit einhergehenden Geschwindigkeitsverbesserungen zurückgreifen. Bei einer Sprache, die die meiste Arbeit bei der Kompilierung erledigt, muss die Anwendung neu kompiliert werden, um eine Leistungssteigerung der Laufzeitumgebung zu nutzen.

    Objective-C ist eine Obermenge von C, weshalb darin alle Merkmale von C enthalten sind. Um mit Objective-C effektiv zu programmieren, müssen Sie daher die Grundprinzipien sowohl von C als auch von Objective-C verstehen. Insbesondere sind Kenntnisse über das Speichermodell von C hilfreich, um das Speichermodell von Objective-C und das Reference Counting zu begreifen. Dazu müssen Sie sich darüber im Klaren sein, dass ein Zeiger in Objective-C zur Bezeichnung eines Objekts dient. Wenn Sie eine Variable mit einem Verweis auf ein Objekt deklarieren, sieht der dazu erforderliche Code wie folgt aus:

    NSString *someString = @The string;

    Diese Syntax ist fast unverändert von C übernommen. Hier wird die Variable some-String vom Typ NSString* deklariert, also als Zeiger auf ein NSString-Objekt. Alle Objective-C-Objekte müssen auf diese Weise deklariert werden, da der Arbeitsspeicher für Objekte stets auf dem Heap zugewiesen wird und niemals auf dem Stack. Es ist nicht möglich, ein Objective-C-Objekt auf dem Stack zuzuweisen:

    NSString stackString;

    // Fehler: Der Interfacetyp kann nicht statisch zugewiesen werden

    Die Variable someString zeigt auf eine Stelle im Arbeitsspeicher, die auf dem Heap zugewiesen ist und ein NSString-Objekt enthält. Wenn Sie also eine weitere Variable erstellen, die auf denselben Speicherort zeigt, legen Sie damit keine Kopie an, sondern bekommen nur zwei Variablen, die beide auf dasselbe Objekt verweisen:

    NSString *someString = @The string;

    NSString *anotherString = someString;

    Es gibt hier nur eine Instanz von NSString, aber zwei Variablen, die auf sie zeigen. Sie haben den Typ NSString*, was bedeutet, dass im aktuellen Stack-Frame zwei Abschnitte des Arbeitsspeichers von der Größe eines Zeigers zugewiesen sind (vier Byte in einer 32-Bit-Architektur, acht Byte bei 64 Bit). Diese beiden Speicherabschnitte enthalten den gleichen Wert, nämlich die Speicheradresse der NSString-Instanz.

    Diesen Aufbau können Sie in Abbildung 1–1 erkennen. Die für die NSString-Instanz gespeicherten Daten enthalten die erforderlichen Bytes zur Darstellung des eigentlichen Strings.

    Abb. 1–1 Skizze des Arbeitsspeichers mit einer auf dem Heap zugewiesenen Instanz von NSString und zwei auf dem Stack zugewiesenen Zeigern darauf

    Der auf dem Heap zugewiesene Arbeitsspeicher muss direkt verwaltet werden, während der Arbeitsspeicher für die Variablen auf dem Stack automatisch bereinigt wird, wenn der Stack-Frame, auf dem sie sich befinden, vom Stack genommen wird.

    Die Verwaltung des Heap-Arbeitsspeichers ist in Objective-C aus Ihrem Verantwortungsbereich herausabstrahiert worden. Sie müssen nicht malloc und free verwenden, um Arbeitsspeicher für Objekte zuzuweisen und wieder freizugeben. Die Laufzeitumgebung von Objective-C übernimmt dies mithilfe ihrer Speicherverwaltungsarchitektur, des sogenannten Reference Counting (siehe Thema 29).

    Manchmal stoßen Sie in Objective-C jedoch auch auf Variablen, die in ihrer Definition kein * aufweisen und möglicherweise Stack-Arbeitsspeicher nutzen. Solche Variablen halten keine Objective-C-Objekte fest. Ein Beispiel dafür ist CGRect aus dem CoreGraphics-Framework:

    CGRect frame;

    frame.origin.x = 0.0f;

    frame.origin.y = 10.0f;

    frame.size.width = 100.0f;

    frame.size.height = 150.0f;

    Ein CGRect ist eine C-Struktur mit folgender Definition:

    struct CGRect {

    CGPoint origin;

    CGSize size;

    };

    typedef struct CGRect CGRect;

    Diese Arten von Strukturen werden in Systemframeworks verwendet, in denen der Mehraufwand für die Verwendung von Objective-C-Objekten die Leistung beeinträchtigen könnte. Um Objekte zu erstellen, sind Vorgänge erforderlich, die bei der Verwendung von Strukturen nicht anfallen, beispielsweise die Zuweisung und Freigabe von Heap-Speicher. Daher werden gewöhnlich Strukturen von CGRect verwendet, wenn nur Daten von Nichtobjekttypen (wie int, float, double, char usw.) festgehalten werden müssen.

    Bevor Sie beginnen, Objective-C-Code zu schreiben, sollten Sie viel über die Sprache C lesen und sich mit ihrer Syntax vertraut machen. Wenn Sie unvorbereitet mit Objective-C beginnen, können einige Teile der Syntax verwirrend wirken.

    Was Sie sich merken sollten

    • Objective-C ist eine Obermenge von C, die die Sprache um objektorientierte Merkmale ergänzt. Sie verwendet eine Nachrichtenstruktur mit dynamischer Bindung, was bedeutet, dass der Typ eines Objekts zur Laufzeit ermittelt wird. Welcher Code für eine gegebene Nachricht ausgeführt werden soll, bestimmt die Laufzeitkomponente und nicht der Compiler.

    • Kenntnisse der Grundprinzipien von C helfen Ihnen dabei, Objective-C-Code effektiv zu programmieren. Insbesondere sollten Sie mit dem Speichermodell und Zeigern vertraut sein.

    Thema 2: Importieren Sie möglichst keine Header in Header

    Ebenso wie in C und C++ werden auch in Objective-C Header- und Implementierungsdateien verwendet. Für eine in Objective-C geschriebene Klasse wird gewöhnlich jeweils eine Datei jeder Art verwendet. Beide tragen den Namen der Klasse, wobei die Headerdatei die Endung .h aufweist und die Implementierungsdatei die Endung .m. Wenn Sie eine Klasse erstellen, sieht das also wie folgt aus:

    // EOCPerson.h

    #import

    @interface EOCPerson : NSObject

    @property (nonatomic, copy) NSString *firstName;

    @property (nonatomic, copy) NSString *lastName;

    @end

    // EOCPerson.m

    #import EOCPerson.h

    @implementation EOCPerson

    // Implementierung der Methoden

    @end

    Der Import von Foundation.h ist für so ziemlich alle Klassen erforderlich, die Sie jemals in Objective-C erstellen werden. In allen anderen Fällen müssen Sie die grundlegende Headerdatei des Frameworks importieren, aus dem die Oberklasse Ihrer neuen Klasse stammt. Wenn Sie beispielsweise eine iOS-Anwendung schreiben, bilden Sie häufig Unterklassen von UIViewController. In den Headerdateien dieser Klassen müssen Sie UIKit.h importieren.

    Die Klasse ist in diesem Zustand tadellos. Sie importiert zwar das gesamte Foundation-Framework, aber das macht nichts. Da diese Klasse von einer Klasse erbt, die zu Foundation gehört, ist es schließlich sehr wahrscheinlich, dass die Nutzer von EOCPerson große Teile davon verwenden werden. Das Gleiche gilt auch für eine Klasse, die von UIViewController erbt. Auch ihre Nutzer verwenden den Großteil von UIKit.

    Nun kann es sein, dass Sie irgendwann eine neue Klasse namens EOCEmployer für einen Arbeitgeber erstellen und zu dem Schluss kommen, dass eine EOCPerson-Instanz auch über einen Arbeitgeber verfügen sollte. Daher fügen Sie eine Eigenschaft dafür hinzu:

    // EOCPerson.h

    #import

    @interface EOCPerson : NSObject

    @property (nonatomic, copy) NSString *firstName;

    @property (nonatomic, copy) NSString *lastName;

    @property (nonatomic, strong) EOCEmployer *employer;

    @end

    Dabei besteht jedoch das Problem, dass die Klasse EOCEmployer beim Kompilieren von Klassen, die EOCPerson.h importieren, nicht sichtbar ist. Es wäre aber falsch, für alle Klassen, die EOCPerson.h importieren, auch den Import von EOCEmployer.h vorzuschreiben. Also wird oft folgende Zeile am Anfang von EOCPerson.h eingefügt:

    #import EOCEmployer.h

    Das funktioniert zwar, ist aber schlechter Stil. Wenn Sie irgendetwas kompilieren, das EOCPerson nutzt, müssen Sie nicht alle Einzelheiten über EOCEmployer kennen, sondern nur wissen, dass es eine solche Klasse gibt. Tatsächlich gibt es eine Möglichkeit, um dem Compiler genau das mitzuteilen:

    @class EOCEmployer;

    Dies ist eine sogenannte Vorausdeklaration der Klasse. Die resultierende Headerdatei für EOCPerson sieht damit wie folgt aus:

    // EOCPerson.h

    #import

    @class EOCEmployer;

    @interface EOCPerson : NSObject

    @property (nonatomic, copy) NSString *firstName;

    @property (nonatomic, copy) NSString *lastName;

    @property (nonatomic, strong) EOCEmployer *employer;

    @end

    Es ist dann die Implementierungsdatei von EOCPerson, in der die Headerdatei von EOCEmployer importiert wird, da sie alle Einzelheiten des Interface dieser Klasse kennen muss, um sie nutzen zu können. Damit sieht die Implementierungsdatei wie folgt aus:

    // EOCPerson.m

    #import EOCPerson.h

    #import EOCEmployer.h

    @implementation EOCPerson

    // Implementierung der Methoden

    @end

    Durch die Verzögerung des Imports bis zu der Stelle, an der er erforderlich ist, können Sie den Umfang der Klassen beschränken, die ein Benutzer Ihrer Klasse importieren muss. Wenn wir in unserem Beispiel EOCEmployer.h in EOCPerson.h importieren, müsste jeder, der EOCPerson.h importiert, auch den gesamten Inhalt von EOCPEmployer.h importieren. Sollte sich die Kette der Importe noch weiter fortsetzen, importieren Sie am Ende viel mehr als vorgesehen, was die Kompilierungszeit mit Sicherheit verlängert.

    Die Vorausdeklaration lindert auch das Problem, dass die beiden Klassen aufeinander verweisen. Überlegen Sie, was geschieht, wenn in der Headerdatei von EOCEmployer Methoden zum Hinzufügen und Entfernen von Angestellten (employees) definiert sind:

    - (void)addEmployee:(EOCPerson*)person;

    - (void)removeEmployee:(EOCPerson*)person;

    Hier muss die Klasse EOCPerson aus den gleichen Gründen für den Compiler sichtbar sein wie im umgekehrten Fall. Wenn Sie dies jedoch dadurch zu erreichen versuchen, dass Sie den anderen Header in diesen Header importieren, hätten Sie ein Henne-oder-Ei-Problem geschaffen. Wird ein Header geparst, so importiert er den anderen, der wiederum den ersten importiert. Die Verwendung von #import statt #include führt zwar nicht zu einer Endlosschleife, aber immerhin dazu, dass eine der beiden Klassen nicht korrekt kompiliert wird. Wenn Sie mir nicht glauben, dann probieren Sie es selbst aus!

    Manchmal ist es jedoch nötig, einen Header in einen Header zu importieren. Das kann beispielsweise bei einem Header der Fall sein, der die Oberklasse definiert, von der Ihre Klasse erben soll. Auch Protokolle, denen Ihre Klasse gehorchen soll, müssen vollständig definiert und nicht nur im Voraus deklariert werden. Der Compiler muss die Methoden sehen können, die das Protokoll definiert, und nicht nur wissen, dass es dieses Protokoll gibt, wie es bei einer Vorwärtsdeklaration der Fall wäre.

    Betrachten Sie als Beispiel eine Klasse für Rechtecke, die von einer Klasse für allgemeine Formen erbt und mit einem Protokoll konform ist, durch das sie gezeichnet werden kann:

    // EOCRectangle.h

    #import EOCShape.h

    #import EOCDrawable.h

    @interface EOCRectangle : EOCShape

    @property (nonatomic, assign) float width;

    @property (nonatomic, assign) float height;

    @end

    Der zusätzliche Import ist unvermeidlich. Aus diesem Grunde ist es angeraten, solche Protokolle jeweils in ihrer eigenen Headerdatei unterzubringen. Wenn EOCDrawable in einer umfangreicheren Headerdatei enthalten wäre, müssten Sie diese komplett importieren und dabei die zuvor beschriebenen Abhängigkeiten und Kompilierungszeitprobleme in Kauf nehmen.

    Nicht alle Protokolle müssen aber in jeweils eigene Dateien gestellt werden. Das gilt beispielsweise für Delegate-Protokolle (siehe Thema 23). Solche Protokolle sind nur dann sinnvoll, wenn sie zusammen mit der Klasse definiert sind, für die sie als Delegate fungieren. In diesen Fällen bietet es sich an, die Implementierung des Delegates durch Ihre Klasse in die Klassenerweiterungskategorie zu stellen (siehe Thema 27). Damit können Sie den Import des Headers mit dem Delegate-Protokoll in der Implementierungsdatei vornehmen anstatt in der öffentlichen Headerdatei.

    Sobald Sie irgendetwas in eine Headerdatei importieren, sollten Sie sich immer fragen, ob es wirklich nötig ist. Wenn der Import auch im Voraus deklariert werden kann, sollten Sie lieber das tun. Wird der Import für die Verwendung in einer Eigenschaft oder einer Instanzvariable oder zur Konformität mit einem Protokoll gebraucht, sollten Sie ihn die Klassenerweiterungskategorie verlagern (siehe Thema 27). Dadurch halten Sie die Kompilierungszeit so kurz wie möglich und verringern Abhängigkeiten, die zu Problemen bei der Wartung oder bei der Bereitstellung von Teilen Ihres Codes in öffentlichen APIs führen könnten.

    Was Sie sich merken sollten

    • Importieren Sie Header immer an der tiefstmöglichen Stelle. Das bedeutet gewöhnlich, im Header eine Vorausdeklaration vorzunehmen und die zugehörigen Header in der Implementierungsdatei zu importieren. Dadurch vermeiden Sie weitgehend eine Kopplung der Klassen.

    • Manchmal sind Vorausdeklarationen nicht möglich, beispielsweise bei der Deklaration der Protokollkonformität. In solchen Fällen sollten Sie die Deklaration nach Möglichkeit in die Klassenerweiterungskategorie stellen. Anderenfalls importieren Sie einen Header, der nur das gewünschte Protokoll definiert.

    Thema 3: Bevorzugen Sie Literale gegenüber gleichwertigen Methoden

    Bei der Verwendung von Objective-C werden Sie immer wieder auf eine Handvoll Klassen stoßen, die alle zum Foundation-Framework gehören. Rein technisch gesehen ist es zwar nicht erforderlich, Foundation zu verwenden, um Objective-C-Code zu schreiben, aber in der Praxis werden Sie es gewöhnlich tun. Die allgegenwärtigen Klassen sind NSString, NSNumber, NSArray und NSDictionary, wobei schon aus den Namen abzulesen ist, für welche Datenstrukturen sie stehen.

    Objective-C ist für eine wortreiche Syntax bekannt. Das stimmt zwar, doch seit der Einführung von Objective-C 1.0 gibt es auch eine sehr einfache Möglichkeit, um ein NSString-Objekt zu erstellen, nämlich das sogenannte Stringliteral, das wie folgt aussieht:

    NSString *someString = @Effective Objective-C 2.0;

    Ohne diese Art von Syntax müssten Sie ein NSString-Objekt mit den üblichen Methodenaufrufen alloc und init zuweisen und initialisieren. Zum Glück wurde die Literalsyntax in den neuesten Versionen des Compilers auch auf Instanzen von NSNumber, NSArray und NSDictionary ausgedehnt. Mit dieser Syntax können Sie den Umfang des Quellcodes verringern und ihn besser lesbar gestalten.

    Zahlenliterale

    Manchmal müssen Sie einen Integer, eine Fließkommazahl oder einen booleschen Wert in ein Objective-C-Objekt packen. Dazu verwenden Sie die Klasse NSNumber, die mit verschiedenen Arten von Zahlen umgehen kann. Ohne die Literalsyntax erstellen Sie wie folgt eine Instanz davon:

    NSNumber *someNumber = [NSNumber numberWithInt:1];

    Dadurch wird ein Satz erstellt, der auf den Integer 1 gesetzt ist. Mit einem Literal geht das jedoch einfacher:

    NSNumber *someNumber = @1;

    Wie Sie sehen, ist die Literalsyntax viel kompakter. Das ist aber noch nicht alles. Die Syntax deckt auch alle anderen Arten von Daten ab, die NSNumber-Instanzen darstellen können. Betrachten Sie die folgenden Beispiele:

    NSNumber *intNumber = @1;

    NSNumber *floatNumber = @2.5f;

    NSNumber *doubleNumber = @3.14159;

    NSNumber *boolNumber = @YES;

    NSNumber *charNumber = @'a';

    Die Literalsyntax funktioniert auch bei Ausdrücken:

    int x = 5;

    float y = 6.32f;

    NSNumber *expressionNumber = @(x * y);

    Der Einsatz von Literalen für Zahlen ist äußerst praktisch. Dadurch wird die Verwendung von NSNumber-Objekten viel deutlicher, da die Deklaration nun hauptsächlich aus dem Wert statt aus den überflüssigen Syntaxelementen besteht.

    Array-Literale

    Arrays sind sehr häufig verwendete Datenstrukturen. Vor der Einführung von Literalen hätten Sie ein Array wie folgt erstellen müssen:

    NSArray *animals =

        [NSArray arrayWithObjects:@cat, @dog, @mouse,

    Enjoying the preview?
    Page 1 of 1