Ich kenne das HIG (was sehr praktisch ist!), Aber welche Programmierpraktiken verwenden Sie beim Schreiben von Objective-C und insbesondere bei der Verwendung von Cocoa (oder CocoaTouch).
Ich kenne das HIG (was sehr praktisch ist!), Aber welche Programmierpraktiken verwenden Sie beim Schreiben von Objective-C und insbesondere bei der Verwendung von Cocoa (oder CocoaTouch).
Antworten:
Es gibt einige Dinge, mit denen ich begonnen habe und die ich nicht für Standard halte:
1) Mit dem Aufkommen von Eigenschaften verwende ich nicht mehr "_", um "private" Klassenvariablen voranzustellen. Wenn andere Klassen auf eine Variable zugreifen können, sollte es dann keine Eigenschaft dafür geben? Ich mochte das Präfix "_" immer nicht, um Code hässlicher zu machen, und jetzt kann ich es weglassen.
2) Wenn ich von privaten Dingen spreche, ziehe ich es vor, private Methodendefinitionen in der .m-Datei in einer Klassenerweiterung wie folgt zu platzieren:
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass
Warum die .h-Datei mit Dingen überladen, die Außenstehende nicht interessieren sollten? Das leere () funktioniert für private Kategorien in der .m-Datei und gibt Kompilierungswarnungen aus, wenn Sie die deklarierten Methoden nicht implementieren.
3) Ich habe es mir zur Aufgabe gemacht, Dealloc am Anfang der .m-Datei direkt unter den @synthesize-Anweisungen zu platzieren. Sollte das, was Sie freigeben, nicht ganz oben auf der Liste der Dinge stehen, über die Sie in einer Klasse nachdenken möchten? Dies gilt insbesondere in einer Umgebung wie dem iPhone.
3.5) Machen Sie in Tabellenzellen jedes Element (einschließlich der Zelle selbst) für die Leistung undurchsichtig. Das bedeutet, in allem die richtige Hintergrundfarbe einzustellen.
3.6) Wenn Sie eine NSURLConnection verwenden, möchten Sie in der Regel die Delegate-Methode implementieren:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
Ich finde, dass die meisten Webanrufe sehr einzigartig sind und eher die Ausnahme als die Regel sind, nach der Antworten zwischengespeichert werden sollen, insbesondere bei Webdienstanrufen. Durch das Implementieren der gezeigten Methode wird das Zwischenspeichern von Antworten deaktiviert.
Interessant sind auch einige gute iPhone-spezifische Tipps von Joseph Mattiello (erhalten in einer iPhone-Mailingliste). Es gibt noch mehr, aber diese waren die allgemein nützlichsten, die ich dachte (beachten Sie, dass einige Bits jetzt geringfügig vom Original bearbeitet wurden, um Details in den Antworten aufzunehmen):
4) Verwenden Sie nur doppelte Genauigkeit, wenn Sie müssen, z. B. wenn Sie mit CoreLocation arbeiten. Stellen Sie sicher, dass Sie Ihre Konstanten mit 'f' beenden, damit gcc sie als Floats speichert.
float val = someFloat * 2.2f;
Dies ist vor allem dann wichtig, wenn someFloat
es sich tatsächlich um ein Double handelt. Sie benötigen keine Mathematik im gemischten Modus, da Sie beim Speichern die Genauigkeit von 'val' verlieren. Während Gleitkommazahlen in der Hardware von iPhones unterstützt werden, kann die Ausführung von Arithmetik mit doppelter Genauigkeit im Gegensatz zur einfachen Genauigkeit noch länger dauern. Verweise:
Bei älteren Telefonen arbeiten Berechnungen angeblich mit der gleichen Geschwindigkeit, aber Sie können mehr Komponenten mit einfacher Genauigkeit in Registern als doppelte haben, sodass bei vielen Berechnungen die Genauigkeit mit einfacher Genauigkeit schneller ist.
5) Legen Sie Ihre Eigenschaften als fest nonatomic
. Sie sind atomic
standardmäßig und bei der Synthese wird Semaphorcode erstellt, um Multithreading-Probleme zu vermeiden. 99% von Ihnen müssen sich wahrscheinlich keine Sorgen machen, und der Code ist viel weniger aufgebläht und speichereffizienter, wenn er auf nichtatomar eingestellt ist.
6) SQLite kann eine sehr, sehr schnelle Möglichkeit sein, große Datenmengen zwischenzuspeichern. Eine Kartenanwendung kann beispielsweise ihre Kacheln in SQLite-Dateien zwischenspeichern. Der teuerste Teil ist die Festplatten-E / A. Vermeiden Sie viele kleine Schreibvorgänge durch Senden BEGIN;
und COMMIT;
zwischen großen Blöcken. Wir verwenden zum Beispiel einen 2-Sekunden-Timer, der bei jeder neuen Übermittlung zurückgesetzt wird. Wenn es abläuft, senden wir COMMIT; , was dazu führt, dass alle Ihre Schreibvorgänge in einem großen Block ablaufen. SQLite speichert Transaktionsdaten auf der Festplatte. Durch dieses Begin / End-Wrapping wird die Erstellung vieler Transaktionsdateien vermieden und alle Transaktionen in einer Datei zusammengefasst.
Außerdem blockiert SQL Ihre GUI, wenn sie sich in Ihrem Hauptthread befindet. Wenn Sie eine sehr lange Abfrage haben, ist es eine gute Idee, Ihre Abfragen als statische Objekte zu speichern und Ihre SQL in einem separaten Thread auszuführen. Stellen Sie sicher, dass alle Elemente, die die Datenbank für Abfragezeichenfolgen ändern, in @synchronize() {}
Blöcke eingeschlossen werden. Lassen Sie bei kurzen Fragen die Dinge einfach im Haupt-Thread, um die Arbeit zu vereinfachen.
Weitere Tipps zur SQLite-Optimierung finden Sie hier, obwohl das Dokument veraltet erscheint. Viele der Punkte sind wahrscheinlich noch gut.
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Wenn Methoden oder Funktionen ein Formatzeichenfolgenargument verwenden, sollten Sie sicherstellen, dass Sie die Kontrolle über den Inhalt der Formatzeichenfolge haben.
Wenn Sie beispielsweise Zeichenfolgen protokollieren, ist es verlockend, die Zeichenfolgenvariable als einziges Argument an Folgendes zu übergeben NSLog
:
NSString *aString = // get a string from somewhere;
NSLog(aString);
Das Problem dabei ist, dass die Zeichenfolge Zeichen enthalten kann, die als Formatzeichenfolgen interpretiert werden. Dies kann zu fehlerhaften Ausgaben, Abstürzen und Sicherheitsproblemen führen. Stattdessen sollten Sie die Zeichenfolgenvariable durch eine Formatzeichenfolge ersetzen:
NSLog(@"%@", aString);
Verwenden Sie Standardkonventionen und -terminologien für die Benennung und Formatierung von Kakao und nicht das, was Sie von einer anderen Umgebung gewohnt sind. Es gibt viele Cocoa-Entwickler, und wenn einer von ihnen anfängt, mit Ihrem Code zu arbeiten, ist es viel zugänglicher, wenn er ähnlich aussieht und sich wie anderer Cocoa-Code anfühlt.
Beispiele dafür, was zu tun ist und was nicht:
id m_something;
in der Schnittstelle eines Objekts und nennen Sie es eine Mitgliedsvariable oder ein Feld . Verwenden Sie something
oder _something
für seinen Namen und nennen Sie es eine Instanzvariable .-getSomething
. Der richtige Kakaoname ist gerecht -something
.-something:
. es sollte sein-setSomething:
-[NSObject performSelector:withObject:]
nicht NSObject::performSelector
.Was auch immer Sie tun, verwenden Sie keine ungarische Win16 / Win32-Notation. Sogar Microsoft gab dies mit der Umstellung auf die .NET-Plattform auf.
In der Vergangenheit war die Speicherverwaltung von Steckdosen schlecht. Derzeit wird empfohlen, Verkaufsstellen als Eigenschaften zu deklarieren:
@interface MyClass :NSObject {
NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end
Durch die Verwendung von Eigenschaften wird die Semantik der Speicherverwaltung deutlich. Es bietet auch ein konsistentes Muster, wenn Sie die Synthese von Instanzvariablen verwenden.
HINWEIS: Unter Xcode 4 ist dies jetzt in die IDE integriert.
Sie verwenden den Clang Static Analyzer, um - nicht überraschend - Ihren C- und Objective-C-Code (noch kein C ++) unter Mac OS X 10.5 zu analysieren. Es ist trivial zu installieren und zu verwenden:
cd
in Ihr Projektverzeichnis.scan-build -k -V xcodebuild
.(Es gibt einige zusätzliche Einschränkungen usw., insbesondere sollten Sie ein Projekt in seiner "Debug" -Konfiguration analysieren - siehe http://clang.llvm.org/StaticAnalysisUsage.html für Details - das ist aber mehr oder weniger worauf es ankommt.)
Der Analysator erstellt dann eine Reihe von Webseiten für Sie, die die wahrscheinliche Speicherverwaltung und andere grundlegende Probleme anzeigen, die der Compiler nicht erkennen kann.
Dies ist subtil, aber praktisch. Wenn Sie sich als Delegierter an ein anderes Objekt übergeben, setzen Sie den Delegierten dieses Objekts vor Ihnen zurück dealloc
.
- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}
Auf diese Weise stellen Sie sicher, dass keine Delegatmethoden mehr gesendet werden. Wenn Sie dealloc
im Äther sind und verschwinden möchten, möchten Sie sicherstellen, dass Ihnen nichts mehr versehentlich Nachrichten senden kann. Denken Sie daran, dass self.someObject von einem anderen Objekt beibehalten werden könnte (es könnte ein Singleton oder im Autorelease-Pool sein oder was auch immer), und bis Sie ihm sagen "Hör auf, mir Nachrichten zu senden!" ist Freiwild.
Wenn Sie sich an diese Gewohnheit gewöhnen, werden Sie vor vielen seltsamen Abstürzen bewahrt, die beim Debuggen schmerzhaft sind.
Das gleiche Prinzip gilt für die Beobachtung von Schlüsselwerten und auch für NSNotifications.
Bearbeiten:
Noch defensiver, ändern:
self.someObject.delegate = NULL;
in:
if (self.someObject.delegate == self)
self.someObject.delegate = NULL;
Memory Management Programming Guide for Cocoa
: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
nil == NULL
. Sie sind genau gleich, außer dass dies nil
ein id
und ein NULL
ist void *
. Ihre Aussage ist nicht wahr.
@ Kendell
Anstatt:
@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end
Verwenden:
@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end
Neu in Objective-C 2.0.
Klassenerweiterungen werden in Apples Objective-C 2.0-Referenz beschrieben.
"Mit Klassenerweiterungen können Sie zusätzliche erforderliche API für eine Klasse an anderen Orten als innerhalb des @ classface-Blocks der Primärklasse deklarieren."
Sie sind also Teil der eigentlichen Klasse - und NICHT zusätzlich zur Klasse eine (private) Kategorie. Subtiler aber wichtiger Unterschied.
()
anstelle von (Private)
(oder einem anderen Kategorienamen): Sie können Eigenschaften als Readwrite neu deklarieren, während sie für die Öffentlichkeit nur schreibgeschützt sind. :)
Da Sie normalerweise (1) keine direkte Kontrolle über ihre Lebensdauer haben, können automatisch freigegebene Objekte vergleichsweise lange bestehen bleiben und den Speicherbedarf Ihrer Anwendung unnötig erhöhen. Während dies auf dem Desktop von geringer Bedeutung sein kann, kann dies auf eingeschränkteren Plattformen ein erhebliches Problem sein. Daher wird es auf allen Plattformen und insbesondere auf eingeschränkteren Plattformen als bewährte Methode angesehen, die Verwendung von Methoden zu vermeiden, die zu automatisch freigegebenen Objekten führen würden. Stattdessen wird empfohlen, das Alloc / Init-Muster zu verwenden.
Also eher als:
aVariable = [AClass convenienceMethod];
Wenn möglich, sollten Sie stattdessen Folgendes verwenden:
aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];
Wenn Sie Ihre eigenen Methoden schreiben, die ein neu erstelltes Objekt zurückgeben, können Sie die Namenskonvention von Cocoa nutzen , um dem Empfänger anzuzeigen, dass es freigegeben werden muss, indem Sie dem Methodennamen "new" voranstellen.
Also anstelle von:
- (MyClass *)convenienceMethod {
MyClass *instance = [[[self alloc] init] autorelease];
// configure instance
return instance;
}
du könntest schreiben:
- (MyClass *)newInstance {
MyClass *instance = [[self alloc] init];
// configure instance
return instance;
}
Da der Methodenname mit "neu" beginnt, wissen die BenutzernewObject
Ihrer API, dass sie für die Freigabe des empfangenen Objekts verantwortlich sind (siehe z. B. die Methode von NSObjectController ).
(1) Sie können die Kontrolle übernehmen, indem Sie Ihre eigenen lokalen Autorelease-Pools verwenden. Weitere Informationen hierzu finden Sie unter Autorelease-Pools .
NSAutoreleasePool
. Aber erst nachdem Sie bestätigt haben, dass dies wirklich ein Problem ist. Vorzeitige Optimierung und all das ...
Einige davon wurden bereits erwähnt, aber hier ist, was ich mir auf den ersten Blick vorstellen kann:
#pragma mark [section]
. Normalerweise gruppiere ich nach meinen eigenen Methoden, den Überschreibungen jeder Unterklasse und allen Informationen oder formalen Protokollen. Dies macht es viel einfacher, genau zu dem zu springen, wonach ich suche. Gruppieren Sie zum gleichen Thema ähnliche Methoden (wie die Delegatmethoden einer Tabellenansicht) und kleben Sie sie nicht einfach irgendwo hin.#define
Belieben oder das Zwischenspeichern eines Arrays, anstatt es jedes Mal zu sortieren, wenn die Daten benötigt werden. Ich könnte viel dazu sagen, aber unter dem Strich schreiben Sie keinen Code, bis Sie ihn benötigen oder der Profiler Sie dazu auffordert. Es macht die Wartung auf lange Sicht viel einfacher.NSLog( @"stub" )
einfügen, oder Sie möchten den Überblick behalten.Finish what you start
Sie auch // TODO:
Code zum Vervollständigen markieren, der in der Dropdown-Liste angezeigt wird.
Schreiben Sie Unit-Tests. Sie können viele Dinge in Cocoa testen , die in anderen Frameworks möglicherweise schwieriger sind. Mit UI-Code können Sie beispielsweise im Allgemeinen überprüfen, ob die Dinge so verbunden sind, wie sie sein sollten, und darauf vertrauen, dass sie bei Verwendung funktionieren. Und Sie können Status- und Delegatenmethoden einfach einrichten, um sie zu testen.
Sie haben auch keine Sichtbarkeit von öffentlichen oder geschützten oder privaten Methoden, die das Schreiben von Tests für Ihre Interna behindert.
Goldene Regel: Wenn Sie alloc
dann Sie release
!
UPDATE: Es sei denn, Sie verwenden ARC
copy
, mutableCopy
, new
oder retain
.
Schreiben Sie Objective-C nicht so, als wäre es Java / C # / C ++ / etc.
Ich habe einmal gesehen, wie ein Team, das Java EE-Webanwendungen geschrieben hat, versucht hat, eine Cocoa-Desktopanwendung zu schreiben. Als wäre es eine Java EE-Webanwendung. Es flogen viele AbstractFooFactory und FooFactory und IFoo und Foo herum, wenn alles, was sie wirklich brauchten, eine Foo-Klasse und möglicherweise ein Fooable-Protokoll war.
Um sicherzustellen, dass Sie dies nicht tun, müssen Sie die Unterschiede in der Sprache wirklich verstehen. Beispielsweise benötigen Sie die oben genannten abstrakten Factory- und Factory-Klassen nicht, da Objective-C-Klassenmethoden genauso dynamisch wie Instanzmethoden ausgelöst werden und in Unterklassen überschrieben werden können.
Stellen Sie sicher, dass Sie die Seite Debugging Magic mit einem Lesezeichen versehen . Dies sollte Ihre erste Station sein, wenn Sie Ihren Kopf gegen eine Wand schlagen, während Sie versuchen, die Quelle eines Kakaobugs zu finden.
Beispielsweise erfahren Sie, wie Sie die Methode finden, bei der Sie zuerst Speicher zugewiesen haben, der später zu Abstürzen führt (z. B. während der App-Beendigung).
Versuchen Sie zu vermeiden, was ich jetzt beschlossen habe, Newbiecategoryaholism zu nennen. Wenn Neulinge in Objective-C Kategorien entdecken, werden sie oft wild und fügen jeder existierenden Klasse nützliche kleine Kategorien hinzu ( "Was? Ich kann eine Methode hinzufügen, um eine Zahl in römische Zahlen in NSNumber Rock on umzuwandeln!" ).
Tu das nicht.
Ihr Code wird portabler und verständlicher, ohne dass Dutzende kleiner Kategoriemethoden auf zwei Dutzend Grundklassen verteilt sind.
Wenn Sie wirklich glauben, dass Sie eine Kategoriemethode benötigen, um Code zu optimieren, werden Sie die Methode meistens nie wiederverwenden.
Es gibt auch andere Gefahren, es sei denn, Sie benennen Ihre Kategoriemethoden (und wer ist neben dem absolut verrückten Ddribin?), Besteht die Möglichkeit, dass Apple, ein Plugin oder etwas anderes, das in Ihrem Adressraum ausgeführt wird, dieselbe Kategorie definiert Methode mit dem gleichen Namen mit einer etwas anderen Nebenwirkung ....
OK. Nachdem Sie gewarnt wurden, ignorieren Sie das "Mach diesen Teil nicht". Aber üben Sie extreme Zurückhaltung.
Widerstehen Sie der Unterklasse der Welt. In Cocoa wird viel durch Delegieren und Verwenden der zugrunde liegenden Laufzeit erreicht, in anderen Frameworks durch Unterklassen.
In Java verwenden Sie beispielsweise häufig Instanzen anonymer *Listener
Unterklassen, und in .NET verwenden Sie häufig Ihre EventArgs
Unterklassen. In Cocoa tun Sie dies auch nicht - stattdessen wird die Zielaktion verwendet.
Wenn Sie Zeichenfolgen sortieren, die dem Benutzer angezeigt werden sollen, sollten Sie nicht die einfache compare:
Methode verwenden. Stattdessen sollten Sie immer lokalisierte Vergleichsmethoden wie localizedCompare:
oder verwenden localizedCaseInsensitiveCompare:
.
Weitere Informationen finden Sie unter Suchen, Vergleichen und Sortieren von Zeichenfolgen .
Normalerweise sollten Sie die Funktion "Deklarierte Objective-C 2.0-Eigenschaften" für alle Ihre Eigenschaften verwenden. Wenn sie nicht öffentlich sind, fügen Sie sie in einer Klassenerweiterung hinzu. Durch die Verwendung deklarierter Eigenschaften wird die Speicherverwaltungssemantik sofort klar und Sie können Ihre Dealloc-Methode leichter überprüfen. Wenn Sie Ihre Eigenschaftsdeklarationen gruppieren, können Sie sie schnell scannen und mit der Implementierung Ihrer Dealloc-Methode vergleichen.
Sie sollten gründlich überlegen, bevor Sie Eigenschaften nicht als "nichtatomar" markieren. Wie im Handbuch zur Programmiersprache Objective C erwähnt , sind Eigenschaften standardmäßig atomar und verursachen einen erheblichen Overhead. Darüber hinaus macht es Ihre Anwendung nicht threadsicher, wenn Sie einfach alle Ihre Eigenschaften atomar machen. Beachten Sie natürlich auch, dass Sie, wenn Sie nicht 'nichtatomar' angeben und Ihre eigenen Zugriffsmethoden implementieren (anstatt sie zu synthetisieren), diese atomar implementieren müssen.
Wie diese Frage vermerkt, werden Nachrichten annil
in Objective-C gültig. Obwohl dies häufig von Vorteil ist und zu saubererem und natürlicherem Code führt, kann die Funktion gelegentlich zu eigenartigen und schwer auffindbaren Fehlern führen, wenn Sie einen nil
Wert erhalten, den Sie nicht erwartet haben.
Verwenden Sie NSAssert und Freunde. Ich benutze die ganze Zeit nil als gültiges Objekt ... besonders das Senden von Nachrichten an nil ist in Obj-C vollkommen gültig. Wenn ich jedoch wirklich den Status einer Variablen überprüfen möchte, verwende ich NSAssert und NSParameterAssert, um Probleme leicht aufzuspüren.
Einfach, aber oft vergessen. Nach Spezifikation:
Im Allgemeinen müssen Methoden in verschiedenen Klassen mit demselben Selektor (demselben Namen) auch denselben Rückgabe- und Argumenttyp verwenden. Diese Einschränkung wird vom Compiler auferlegt, um eine dynamische Bindung zu ermöglichen.
In diesem Fall wird davon ausgegangen, dass alle gleichnamigen Selektoren, auch wenn sie sich in verschiedenen Klassen befinden , identische Rückgabe- / Argumenttypen haben. Hier ist ein einfaches Beispiel.
@interface FooInt:NSObject{}
-(int) print;
@end
@implementation FooInt
-(int) print{
return 5;
}
@end
@interface FooFloat:NSObject{}
-(float) print;
@end
@implementation FooFloat
-(float) print{
return 3.3;
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id f1=[[FooFloat alloc]init];
//prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
NSLog(@"%f",[f1 print]);
FooFloat* f2=[[FooFloat alloc]init];
//prints 3.3 expectedly as the static type is FooFloat
NSLog(@"%f",[f2 print]);
[f1 release];
[f2 release]
[pool drain];
return 0;
}
Wenn Sie Leopard (Mac OS X 10.5) oder höher verwenden, können Sie mit der Anwendung Instruments Speicherlecks suchen und verfolgen. Wählen Sie nach dem Erstellen Ihres Programms in Xcode Ausführen> Mit Leistungstool starten> Lecks.
Auch wenn Ihre App keine Lecks aufweist, halten Sie Objekte möglicherweise zu lange in der Nähe. In Instruments können Sie hierfür das ObjectAlloc-Instrument verwenden. Wählen Sie das ObjectAlloc-Instrument in Ihrem Instrumentendokument aus und rufen Sie die Details des Instruments auf (falls es noch nicht angezeigt wird), indem Sie Ansicht> Detail wählen (daneben sollte ein Häkchen angezeigt werden). Stellen Sie unter "Allocation Lifespan" im ObjectAlloc-Detail sicher, dass Sie das Optionsfeld neben "Created & Still Living" aktivieren.
Wenn Sie jetzt die Aufzeichnung Ihrer Anwendung beenden, zeigt Ihnen die Auswahl des ObjectAlloc-Tools in der Spalte "# Net" an, wie viele Verweise auf jedes noch lebende Objekt in Ihrer Anwendung vorhanden sind. Stellen Sie sicher, dass Sie nicht nur Ihre eigenen Klassen betrachten, sondern auch die Klassen der Objekte der obersten Ebene Ihrer NIB-Dateien. Wenn Sie beispielsweise keine Fenster auf dem Bildschirm haben und Verweise auf ein noch lebendes NSW-Fenster sehen, haben Sie es möglicherweise nicht in Ihrem Code veröffentlicht.
Aufräumen im Dealloc.
Dies ist eines der am einfachsten zu vergessenden Dinge - insb. beim Codieren bei 150mph. Bereinigen Sie immer, immer, immer Ihre Attribute / Mitgliedsvariablen im Dealloc.
Ich verwende gerne Objc 2-Attribute - mit der neuen Punktnotation -, sodass die Bereinigung schmerzlos ist. Oft so einfach wie:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
Dies kümmert sich um die Freigabe für Sie und setzt das Attribut auf NULL (was ich als defensive Programmierung betrachte - falls eine andere Methode weiter unten im Dealloc erneut auf die Mitgliedsvariable zugreift - selten, aber möglich möglich).
Wenn GC in 10.5 aktiviert ist, wird dies nicht mehr so oft benötigt. Möglicherweise müssen Sie jedoch noch andere von Ihnen erstellte Ressourcen bereinigen. Dies können Sie stattdessen in der Finalisierungsmethode tun.
-init
und -dealloc
Methoden verwendet werden sollen oder nicht, finden Sie hier: mikeash.com/?page=pyblog/…
Alle diese Kommentare sind großartig, aber ich bin wirklich überrascht, dass niemand den vor einiger Zeit veröffentlichten Objective-C Style Guide von Google erwähnt hat . Ich denke, sie haben sehr gründliche Arbeit geleistet.
Auch semi-verwandtes Thema (mit Platz für mehr Antworten!):
Was sind diese kleinen Xcode-Tipps und Tricks, die Sie vor etwa 2 Jahren gerne gewusst hätten? .
Vergessen Sie nicht, dass NSWindowController und NSViewController die Objekte der obersten Ebene der von ihnen verwalteten NIB-Dateien freigeben.
Wenn Sie eine NIB-Datei manuell laden, sind Sie dafür verantwortlich, die Objekte der obersten Ebene der NIB freizugeben, wenn Sie damit fertig sind.
Eine ziemlich offensichtliche Option für Anfänger: Verwenden Sie die automatische Einrückungsfunktion von Xcode für Ihren Code. Selbst wenn Sie aus einer anderen Quelle kopieren / einfügen, können Sie nach dem Einfügen des Codes den gesamten Codeblock auswählen, mit der rechten Maustaste darauf klicken und dann die Option auswählen, alles in diesem Block erneut einzurücken.
Xcode analysiert diesen Abschnitt tatsächlich und rückt ihn basierend auf Klammern, Schleifen usw. ein. Es ist viel effizienter, als die Leertaste oder die Tabulatortaste für jede einzelne Zeile zu drücken.
Ich weiß, dass ich dies übersehen habe, als ich zum ersten Mal in die Kakaoprogrammierung eingestiegen bin.
Stellen Sie sicher, dass Sie die Verantwortlichkeiten für die Speicherverwaltung in Bezug auf NIB-Dateien verstehen. Sie sind dafür verantwortlich, die Objekte der obersten Ebene in jeder von Ihnen geladenen NIB-Datei freizugeben. Lesen Sie die Apple-Dokumentation zu diesem Thema.
Aktivieren Sie alle GCC-Warnungen und deaktivieren Sie diejenigen, die regelmäßig durch Apples Header verursacht werden, um das Rauschen zu reduzieren.
Führen Sie außerdem häufig eine statische Clang-Analyse durch. Sie können es für alle Builds über die Build-Einstellung "Run Static Analyzer" aktivieren.
Schreiben Sie Komponententests und führen Sie sie bei jedem Build aus.
Variablen und Eigenschaften
1 / Halten Sie Ihre Header sauber und verstecken Sie die Implementierung
Fügen Sie keine Instanzvariablen in Ihren Header ein. Private Variablen, die als Eigenschaften in die Klassenfortsetzung eingefügt werden. Öffentliche Variablen werden in Ihrem Header als öffentliche Eigenschaften deklariert. Wenn es nur gelesen werden soll, deklarieren Sie es als schreibgeschützt und überschreiben Sie es als schreibgeschützt in der Klassenfortsetzung. Grundsätzlich verwende ich überhaupt keine Variablen, sondern nur Eigenschaften.
2 / Geben Sie Ihren Eigenschaften einen nicht standardmäßigen Variablennamen, Beispiel:
@synthesize property = property_;
Grund 1: Sie werden Fehler feststellen, die durch das Vergessen von "Selbst" verursacht werden. bei der Zuweisung der Eigenschaft. Grund 2: Aus meinen Experimenten geht hervor, dass Leak Analyzer in Instruments Probleme hat, undichte Eigenschaften mit dem Standardnamen zu erkennen.
3 / Verwenden Sie Retain oder Release niemals direkt auf Eigenschaften (oder nur in sehr außergewöhnlichen Situationen). Weisen Sie ihnen in Ihrem Dealloc einfach eine Null zu. Retain-Eigenschaften sollen das Retain / Release von sich aus handhaben. Sie wissen nie, ob ein Setter beispielsweise keine Beobachter hinzufügt oder entfernt. Sie sollten die Variable nur direkt in ihrem Setter und Getter verwenden.
Ansichten
1 / Fügen Sie jede Ansichtsdefinition in eine xib ein, wenn Sie können (die Ausnahme sind normalerweise dynamische Inhalts- und Ebeneneinstellungen). Das spart Zeit (es ist einfacher als das Schreiben von Code), lässt sich leicht ändern und hält Ihren Code sauber.
2 / Versuchen Sie nicht, Ansichten zu optimieren, indem Sie die Anzahl der Ansichten verringern. Erstellen Sie UIImageView nicht in Ihrem Code anstelle von xib, nur weil Sie Unteransichten hinzufügen möchten. Verwenden Sie stattdessen UIImageView als Hintergrund. Das Ansichtsframework kann problemlos Hunderte von Ansichten verarbeiten.
3 / IBOutlets müssen nicht immer beibehalten werden (oder stark sein). Beachten Sie, dass die meisten Ihrer IBOutlets Teil Ihrer Ansichtshierarchie sind und daher implizit beibehalten werden.
4 / Geben Sie alle IBOutlets in viewDidUnload frei
5 / Rufen Sie viewDidUnload von Ihrer Dealloc-Methode auf. Es wird nicht implizit genannt.
Erinnerung
1 / Autorelease-Objekte beim Erstellen. Viele Fehler werden verursacht, wenn Sie Ihren Release-Aufruf in einen if-else-Zweig oder nach einer return-Anweisung verschieben. Release anstelle von Autorelease sollte nur in Ausnahmesituationen verwendet werden - z. B. wenn Sie auf einen Runloop warten und nicht möchten, dass Ihr Objekt zu früh automatisch freigegeben wird.
2 / Auch wenn Sie Authomatic Reference Counting verwenden, müssen Sie genau wissen, wie Retain-Release-Methoden funktionieren. Die manuelle Verwendung von Retain-Release ist nicht komplizierter als ARC. In beiden Fällen müssen Sie sich mit Lecks und Retain-Zyklen befassen. Verwenden Sie Retain-Release manuell für große Projekte oder komplizierte Objekthierarchien.
Bemerkungen
1 / Machen Sie Ihren Code automatisch dokumentiert. Jeder Variablenname und Methodenname sollte angeben, was er tut. Wenn der Code korrekt geschrieben ist (Sie benötigen viel Übung), benötigen Sie keine Codekommentare (nicht dasselbe wie Dokumentationskommentare). Algorithmen können kompliziert sein, aber der Code sollte immer einfach sein.
2 / Manchmal benötigen Sie einen Kommentar. Normalerweise, um ein nicht offensichtliches Codeverhalten oder einen Hack zu beschreiben. Wenn Sie der Meinung sind, dass Sie einen Kommentar schreiben müssen, versuchen Sie zunächst, den Code so umzuschreiben, dass er einfacher und ohne Kommentare ist.
Vertiefung
1 / Erhöhen Sie die Einrückung nicht zu stark. Der größte Teil Ihres Methodencodes sollte auf Methodenebene eingerückt sein. Verschachtelte Blöcke (wenn, für usw.) verringern die Lesbarkeit. Wenn Sie drei verschachtelte Blöcke haben, sollten Sie versuchen, die inneren Blöcke in eine separate Methode zu verschieben. Vier oder mehr verschachtelte Blöcke sollten niemals verwendet werden. Wenn sich der größte Teil Ihres Methodencodes in einem if befindet, negieren Sie die if-Bedingung. Beispiel:
if (self) {
//... long initialization code ...
}
return self;
if (!self) {
return nil;
}
//... long initialization code ...
return self;
Verstehen Sie C-Code, hauptsächlich C-Strukturen
Beachten Sie, dass Obj-C nur eine leichte OOP-Ebene über der C-Sprache ist. Sie sollten verstehen, wie grundlegende Codestrukturen in C funktionieren (Aufzählungen, Strukturen, Arrays, Zeiger usw.). Beispiel:
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);
ist das gleiche wie:
CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;
Und viele mehr
Bewahren Sie Ihr eigenes Dokument mit Codierungsstandards auf und aktualisieren Sie es häufig. Versuchen Sie, aus Ihren Fehlern zu lernen. Verstehen Sie, warum ein Fehler erstellt wurde, und versuchen Sie, ihn mithilfe von Codierungsstandards zu vermeiden.
Unsere Codierungsstandards umfassen derzeit etwa 20 Seiten, eine Mischung aus Java-Codierungsstandards, Google Obj-C / C ++ - Standards und unseren eigenen Ergänzungen. Dokumentieren Sie Ihren Code, verwenden Sie Standard-Einrückungen, Leerzeichen und Leerzeilen an den richtigen Stellen usw.
Seien Sie funktionaler .
Objective-C ist eine objektorientierte Sprache, die jedoch den Funktionsstil des Cocoa-Frameworks berücksichtigt und in vielen Fällen als Funktionsstil konzipiert ist.
Es gibt eine Trennung der Veränderlichkeit. Verwenden Sie unveränderliche Klassen als primäres und veränderliches Objekt als sekundäres. Verwenden Sie beispielsweise hauptsächlich NSArray und NSMutableArray nur bei Bedarf.
Es gibt reine Funktionen. Nicht so viele, kaufen viele Framework-APIs sind wie reine Funktion konzipiert. Schauen Sie sich Funktionen wie CGRectMake()
oder an CGAffineTransformMake()
. Offensichtlich sieht die Zeigerform effizienter aus. Indirekte Argumente mit Zeigern können jedoch keine Nebenwirkung bieten. Entwerfen Sie Strukturen so weit wie möglich. Trennen Sie gerade Statusobjekte. Verwenden Sie -copy
anstelle von, -retain
wenn Sie einen Wert an ein anderes Objekt übergeben. Weil der gemeinsame Zustand die Mutation zum Wert in einem anderen Objekt stillschweigend beeinflussen kann. Kann also nicht nebenwirkungsfrei sein. Wenn Sie einen Wert von extern von Objekt haben, kopieren Sie ihn. Daher ist es auch wichtig, den gemeinsamen Status so minimal wie möglich zu gestalten.
Haben Sie jedoch keine Angst davor, auch unreine Funktionen zu verwenden.
Es gibt eine faule Bewertung. Sehen Sie so etwas wie -[UIViewController view]
Eigentum. Die Ansicht wird nicht erstellt, wenn das Objekt erstellt wird. Es wird erstellt, wenn der Anrufer die view
Eigenschaft zum ersten Mal liest . UIImage
wird erst geladen, wenn es tatsächlich gezeichnet wird. Es gibt viele Implementierungen wie dieses Design. Diese Art von Designs ist sehr hilfreich für das Ressourcenmanagement, aber wenn Sie das Konzept der verzögerten Bewertung nicht kennen, ist es nicht einfach, das Verhalten dieser Designs zu verstehen.
Es gibt Schließung. Verwenden Sie so oft wie möglich C-Blöcke. Dies wird Ihr Leben erheblich vereinfachen. Lesen Sie jedoch noch einmal die Blockspeicherverwaltung, bevor Sie sie verwenden.
Es gibt halbautomatische GC. NSAutoreleasePool. Verwenden Sie -autorelease
primäre. Verwenden Sie die manuelle -retain/-release
Sekundärseite, wenn Sie sie wirklich brauchen. (Beispiel: Speicheroptimierung, explizites Löschen von Ressourcen)
autorelease
, dass der Speicher im Allgemeinen länger gehalten wird, und manuell retain/release
kann der Speicherverbrauch in diesem Fall reduziert werden. Es sollte jedoch eine Anleitung für die Optimierung von Sonderfällen sein (auch wenn Sie sich immer fühlen!), Kann nicht der Grund sein, vorzeitige Optimierung als Praxis zu verallgemeinern . Und tatsächlich ist Ihr Vorschlag nicht entgegengesetzt zu mir. Ich erwähnte es als Fall der Notwendigkeit :)