Effektiv Objective-C 2.0 programmieren: 52 Profi-Lösungen für bessere iOS- und OS-X-Programmierung
()
About this ebook
• 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
Related to Effektiv Objective-C 2.0 programmieren
Related ebooks
Kompaktkurs C# 5.0 Rating: 0 out of 5 stars0 ratingsJavaScript und TypeScript für C#-Entwickler Rating: 0 out of 5 stars0 ratingsKompaktkurs C# 7 Rating: 0 out of 5 stars0 ratingsEinblicke in C# 6.0 Rating: 0 out of 5 stars0 ratingsModerne Datenzugriffslösungen mit Entity Framework 6 Rating: 0 out of 5 stars0 ratingsJavaScript Performance Rating: 0 out of 5 stars0 ratingsJavaScript für Java-Entwickler Rating: 0 out of 5 stars0 ratingsDSL mit Xtext/Xtend. Luecken(x)text Rating: 0 out of 5 stars0 ratingsAgile Softwareentwicklung mit C# (Microsoft Press): Best Practices und Patterns für flexiblen und adaptiven C#-Code Rating: 0 out of 5 stars0 ratingsWebtechnologien - All in One: Eine praxisorientierte Einführung in moderne Webtechnologien Rating: 0 out of 5 stars0 ratingsArchitekturpatterns mit Python: Test-Driven Development, Domain-Driven Design und Event-Driven Microservices praktisch umgesetzt Rating: 0 out of 5 stars0 ratings.NET-Praxis: Tipps und Tricks zu .NET und Visual Studio Rating: 0 out of 5 stars0 ratingsSoftware Development Trends: Wegweisende Beiträge für eine neue IT: Wegweisende Beiträge für eine neue IT Rating: 0 out of 5 stars0 ratingsVue.js kurz & gut Rating: 0 out of 5 stars0 ratingsTextverarbeitung mit Microsoft Word 2021/365 (Syllabus 6.0): ECDL Base Modul (Schweiz) Rating: 0 out of 5 stars0 ratingsJava 9 – Die Neuerungen: Syntax- und API-Erweiterungen und Modularisierung im Überblick Rating: 0 out of 5 stars0 ratingsEinstieg in TypeScript: Grundlagen für Entwickler Rating: 0 out of 5 stars0 ratingsReact Native: Native Apps parallel für Android und iOS entwickeln Rating: 0 out of 5 stars0 ratingsBenutzerhandbuch zu ProjectLibre 1.9.3 Rating: 0 out of 5 stars0 ratingsNebenläufige Programmierung mit Java: Konzepte und Programmiermodelle für Multicore-Systeme Rating: 0 out of 5 stars0 ratingsF#: Ein praktischer Einstieg Rating: 0 out of 5 stars0 ratingsWebanwendungen erstellen mit Vue.js: MVVM-Muster für konventionelle und Single-Page-Webseiten Rating: 0 out of 5 stars0 ratingsCDI - Dependency Injection in Java EE 7: Dependency Injection in Java EE 7 Rating: 0 out of 5 stars0 ratingsNext Level JavaScript: Schlagworte Rating: 0 out of 5 stars0 ratingsSprachenkompendium: Vala, Go und Rust Rating: 0 out of 5 stars0 ratingsBigData mit JavaScript visualisieren: D3.js für die Darstellung großer Datenmengen einsetzen Rating: 0 out of 5 stars0 ratingsHandbuch Infrastructure as Code: Prinzipien, Praktiken und Patterns für eine cloudbasierte IT-Infrastruktur Rating: 0 out of 5 stars0 ratingsASP.NET Core: Eine Einführung Rating: 0 out of 5 stars0 ratingsWindows 10 Update - Oktober 2018: Alles zum neuen Herbst-Update Rating: 0 out of 5 stars0 ratings
Programming For You
Programmieren von Kopf bis Fuß Rating: 4 out of 5 stars4/5Algorithmen: Grundlagen und Implementierung Rating: 0 out of 5 stars0 ratingsLinux Grundlagen - Ein Einstieg in das Linux-Betriebssystem Rating: 0 out of 5 stars0 ratingsJavaScript kurz & gut Rating: 3 out of 5 stars3/5Python kurz & gut: Für Python 3.x und 2.7 Rating: 3 out of 5 stars3/5Hacken mit Python und Kali-Linux: Entwicklung eigener Hackingtools mit Python unter Kali-Linux Rating: 0 out of 5 stars0 ratingsGit kurz & gut Rating: 0 out of 5 stars0 ratingsWeniger schlecht programmieren Rating: 4 out of 5 stars4/5Raspberry Pi: Mach's einfach: Die kompakteste Gebrauchsanweisung mit 222 Anleitungen. Geeignet für Raspberry Pi 3 Modell B / B+ Rating: 0 out of 5 stars0 ratingsDas große Python3 Workbook: Mit vielen Beispielen und Übungen - Programmieren leicht gemacht! Rating: 4 out of 5 stars4/5Programmieren lernen mit Python 3: Schnelleinstieg für Beginner Rating: 0 out of 5 stars0 ratings.NET-Praxis: Tipps und Tricks zu .NET und Visual Studio Rating: 0 out of 5 stars0 ratingsMikrocontroller in der Elektronik: Mikrocontroller programmieren und in der Praxis einsetzen Rating: 0 out of 5 stars0 ratingsLinux Befehlsreferenz: Schnelleinstieg in die Arbeit mit der Konsole, regulären Ausdrücken und Shellscripting Rating: 0 out of 5 stars0 ratingsC von Kopf bis Fuß Rating: 3 out of 5 stars3/5SQL von Kopf bis Fuß Rating: 4 out of 5 stars4/5New Game Plus: Perspektiven der Game Studies. Genres - Künste - Diskurse (Bild und Bit. Studien zur digitalen Medienkultur) Rating: 0 out of 5 stars0 ratingsEigene Spiele programmieren – Python lernen: Der spielerische Weg zur Programmiersprache Rating: 0 out of 5 stars0 ratingsPython | Schritt für Schritt Programmieren lernen: Der ultimative Anfänger Guide für einen einfachen & schnellen Einstieg Rating: 0 out of 5 stars0 ratingsAndroid-Programmierung kurz & gut Rating: 0 out of 5 stars0 ratingsDie ultimative FRITZ!Box Bibel - Das Praxisbuch 2. aktualisierte Auflage - mit vielen Insider Tipps und Tricks - komplett in Farbe Rating: 0 out of 5 stars0 ratingsRaspberry Pi: Einstieg • Optimierung • Projekte Rating: 5 out of 5 stars5/5Microcontroller für das IoT Rating: 0 out of 5 stars0 ratingsHTML5-Programmierung von Kopf bis Fuß: Webanwendungen mit HTML5 und JavaScript Rating: 0 out of 5 stars0 ratingsSoftwareentwicklungsprozess: Von der ersten Idee bis zur Installation Rating: 0 out of 5 stars0 ratingsProgrammieren für Einsteiger: Teil 1 Rating: 0 out of 5 stars0 ratingsPython lernen – kurz & gut Rating: 0 out of 5 stars0 ratingsPerspektiven für Informatiker 2019: Branchenüberblick, Erfahrungsberichte und Tipps zum Berufseinstieg Rating: 0 out of 5 stars0 ratingsC++: Eine kompakte Einführung Rating: 0 out of 5 stars0 ratings
Reviews for Effektiv Objective-C 2.0 programmieren
0 ratings0 reviews
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
,