Ich kenne das HIGH (was sehr praktisch ist!), Aber welche Programmierpraktiken verwenden Sie beim Schreiben von Objective-C und insbesondere beim Verwenden von Cocoa ( oder Cocoa Touch).
Es gibt ein paar Dinge, die ich angefangen habe und die ich nicht für Standard halte:
1) Mit dem Aufkommen von Eigenschaften benutze ich "_" nicht mehr, um "private" Klassenvariablen voranzustellen. Wenn auf eine Variable von anderen Klassen zugegriffen werden kann, sollte es keine Eigenschaft dafür geben? Ich mochte das Präfix "_" immer nicht, um den 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 der folgenden zu platzieren:
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass
Warum die .h-Datei mit Dingen vollstopfen, die Außenstehende nicht interessieren sollten? Das empty () funktioniert für private Kategorien in der .m-Datei und gibt Kompilierungswarnungen aus, wenn Sie die deklarierten Methoden nicht implementieren.
3) Ich habe beschlossen, dealloc am oberen Rand der .m-Datei, direkt unter den @ synthesize-Direktiven, zu platzieren. Sollte nicht das, worüber Sie sich auflösen, 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 heißt, in allem die passende Hintergrundfarbe einstellen.
3.6. Wenn Sie eine NSURLConnection verwenden, möchten Sie in der Regel möglicherweise die Delegate-Methode implementieren:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
Ich finde, die meisten Webanrufe sind sehr einzigartig und es ist eher die Ausnahme als die Regel, dass Antworten zwischengespeichert werden sollen, insbesondere für Webdienstanrufe. Durch das Implementieren der gezeigten Methode wird das Zwischenspeichern von Antworten deaktiviert.
Interessant sind auch einige gute iPhone-spezifische Tipps von Joseph Mattiello (in einer iPhone-Mailingliste enthalten). 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 die in den Antworten angebotenen Details einzuschließen):
4) Verwenden Sie nur doppelte Genauigkeit, wenn dies erforderlich ist, z. B. bei der Arbeit mit CoreLocation. 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
tatsächlich ein Double sein kann und Sie die Mixed-Mode-Mathematik nicht benötigen, da Sie die Genauigkeit von 'val' beim Speichern verlieren. Während Gleitkommazahlen in der Hardware von iPhones unterstützt werden, dauert es möglicherweise länger, Arithmetik mit doppelter Genauigkeit als mit einfacher Genauigkeit auszuführen. Verweise:
Auf den älteren Telefonen arbeiten angeblich Berechnungen mit der gleichen Geschwindigkeit, aber Sie können mehr Einzelgenauigkeitskomponenten in Registern als Doppelte haben, so dass für viele Berechnungen die Einzelgenauigkeit am Ende schneller ist.
5) Legen Sie Ihre Eigenschaften als nonatomic
fest. Sie sind standardmäßig atomic
und bei der Synthese wird Semaphorcode erstellt, um Multithreading-Probleme zu vermeiden. 99% von Ihnen müssen sich darüber wahrscheinlich keine Gedanken machen, und der Code ist viel weniger aufgebläht und speichereffizienter, wenn er auf Nicht-Atom 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 Disk I/O. Vermeiden Sie viele kleine Schreibvorgänge, indem Sie BEGIN;
Und COMMIT;
Zwischen großen Blöcken senden. Wir verwenden beispielsweise einen 2-Sekunden-Timer, der bei jeder neuen Übermittlung zurückgesetzt wird. Wenn es abläuft, senden wir COMMIT; , wodurch alle Ihre Schreibvorgänge in einem großen Block ausgeführt werden. SQLite speichert die Transaktionsdaten auf der Festplatte. Durch diesen Beginn/Ende-Wrapping wird die Erstellung vieler Transaktionsdateien vermieden, indem alle Transaktionen in einer Datei zusammengefasst werden.
Außerdem blockiert SQL Ihre GUI, wenn sie sich in Ihrem Hauptthread befindet. Wenn Sie eine sehr lange Abfrage haben, empfiehlt es sich, die Abfragen als statische Objekte zu speichern und 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. Bei kurzen Fragen belassen Sie die Informationen einfach auf dem Haupt-Thread, um die Bearbeitung zu vereinfachen.
Weitere Tipps zur SQLite-Optimierung finden Sie hier. Obwohl das Dokument nicht mehr aktuell ist, sind viele der Punkte wahrscheinlich immer 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 NSLog
zu übergeben:
NSString *aString = // get a string from somewhere;
NSLog(aString);
Das Problem dabei ist, dass die Zeichenfolge möglicherweise Zeichen enthält, 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 die Standardkonventionen und -terminologie für die Benennung und Formatierung von Cocoa und nicht das, was Sie aus einer anderen Umgebung gewohnt sind. Es gibt gibt viele Cocoa-Entwickler, und wenn einer von ihnen anfängt, mit Ihrem Code zu arbeiten, ist es viel zugänglicher, wenn es ähnlich aussieht und sich anfühlt wie anderer Cocoa-Code.
Beispiele, was zu tun und was nicht zu tun ist:
id m_something;
in der Schnittstelle eines Objekts und nennen Sie es ein Mitglied Variable oder Feld ; benutze something
oder _something
für seinen Namen und nennen ihn eine Instanzvariable .-getSomething
; der richtige Kakao-Name ist nur -something
.-something:
; es sollte sein -setSomething:
-[NSObject performSelector:withObject:]
, nicht NSObject::performSelector
.Was auch immer Sie tun, nicht Verwenden Sie die ungarische Win16/Win32-Notation. Sogar Microsoft gab dies mit dem Umstieg auf die .NET-Plattform auf.
In der Vergangenheit war die Speicherverwaltung der 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 Speicherverwaltungssemantik deutlich. Es bietet auch ein konsistentes Muster, wenn Sie die Instanzvariablensynthese verwenden.
HINWEIS: Unter Xcode 4 ist dies jetzt in die IDE integriert.
Sie verwenden 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 - the aber das ist mehr oder weniger das, worauf es ankommt.)
Der Analyzer erstellt dann eine Reihe von Webseiten, die die wahrscheinliche Speicherverwaltung und andere grundlegende Probleme anzeigen, die der Compiler nicht erkennen kann.
Dies ist subtil, aber praktisch. Wenn Sie sich als Stellvertreter an ein anderes Objekt übergeben, setzen Sie den Stellvertreter dieses Objekts zurück, bevor Sie dealloc
.
- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}
Auf diese Weise stellen Sie sicher, dass keine Delegate-Methoden mehr gesendet werden. Während Sie im Begriff sind, dealloc
zu tun und im Äther zu verschwinden, möchten Sie sicherstellen, dass Ihnen aus Versehen keine weiteren Nachrichten mehr gesendet werden können. Denken Sie daran, dass self.someObject von einem anderen Objekt beibehalten werden kann (es kann ein Singleton oder ein Objekt im Pool für die automatische Freigabe sein oder was auch immer). Solange Sie nicht sagen, dass Sie keine Nachrichten mehr an mich senden, wird das Objekt für das Objekt gehalten, dessen Zuordnung gerade aufgehoben wird ist faires Spiel.
Wenn Sie sich an diese Gewohnheit gewöhnen, werden Sie vor vielen seltsamen Abstürzen bewahrt, die ein Problem beim Debuggen darstellen.
Dasselbe Prinzip gilt auch für Key Value Observation und NSNotifications.
Bearbeiten:
Noch defensiver, ändern Sie:
self.someObject.delegate = NULL;
in:
if (self.someObject.delegate == self)
self.someObject.delegate = NULL;
@kendell
Anstatt von:
@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 der Objective-C 2.0-Referenz von Apple beschrieben.
"Mit Klassenerweiterungen können Sie zusätzliche erforderliche APIs für eine Klasse an anderen Orten als innerhalb des @ interface-Blocks der Primärklasse deklarieren"
Sie gehören also zur eigentlichen Klasse - und NICHT zu einer (privaten) Kategorie zusätzlich zur Klasse. Subtiler aber wichtiger Unterschied.
Da Sie in der Regel (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 darstellen. Aus diesem Grund wird auf allen Plattformen und insbesondere auf Plattformen mit eingeschränkten Rechten empfohlen, keine Methoden zu verwenden, die zu automatisch freigegebenen Objekten führen. Stattdessen wird empfohlen, das Allocation/Init-Muster zu verwenden.
Also, anstatt:
aVariable = [AClass convenienceMethod];
wo möglich, sollten Sie stattdessen 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 Cocoas Namenskonvention nutzen, um dem Empfänger zu signalisieren, dass es freigegeben werden muss, indem Sie dem Methodennamen "new" voranstellen. .
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 "new" beginnt, wissen die Benutzer Ihrer API, dass sie für die Freigabe des empfangenen Objekts verantwortlich sind (siehe z. B. NSObjectController's newObject
-Methode ).
(1) Sie können die Kontrolle übernehmen, indem Sie Ihre eigenen lokalen Autorelease-Pools verwenden. Weitere Informationen hierzu finden Sie unter Autorelease-Pools .
Einige davon wurden bereits erwähnt, aber hier ist, was ich auf den ersten Blick denken kann:
#pragma mark [section]
. Normalerweise gruppiere ich nach meinen eigenen Methoden, den Außerkraftsetzungen jeder Unterklasse und allen Informationen oder formalen Protokollen. Dies macht es viel einfacher, genau das zu finden, wonach ich suche. Gruppieren Sie ähnliche Methoden (wie die Delegierungsmethoden einer Tabellenansicht) zum selben Thema, und kleben Sie sie nicht einfach irgendwo hin.#define
Ausgeführt wird, oder das Zwischenspeichern eines Arrays, anstatt es jedes Mal zu sortieren Daten werden benötigt. Es gibt eine Menge, die ich dazu sagen könnte, aber im Endeffekt schreiben Sie keinen Code, bis Sie ihn brauchen, oder der Profiler fordert Sie dazu auf. Langfristig sind die Dinge viel einfacher zu warten.NSLog( @"stub" )
einfügen, oder Sie möchten den Überblick behalten.Schreiben Sie Komponententests. Sie können eine Menge von Dingen in Cocoa testen, die in anderen Frameworks möglicherweise schwieriger sind. Mit UI-Code können Sie beispielsweise im Allgemeinen überprüfen, ob die Verbindungen ordnungsgemäß hergestellt wurden, und darauf vertrauen, dass sie bei Verwendung funktionieren. Und Sie können ganz einfach Zustands- und Aufrufmethoden einrichten, um sie zu testen.
Sie haben auch keine Sichtbarkeit für öffentliche oder geschützte oder private Methoden, die Sie beim Schreiben von Tests für Ihre Interna behindert.
Goldene Regel: Wenn Sie alloc
dann Sie release
!
UPDATE: Es sei denn, Sie verwenden ARC
Schreiben Sie Objective-C nicht so, als wäre es Java/C #/C++/etc.
Ich habe einmal ein Team gesehen, das daran gewöhnt war, Java EE-Webanwendungen zu schreiben, und versucht, eine Cocoa-Desktopanwendung zu schreiben. Als wäre es eine Java EE-Webanwendung) viele AbstractFooFactory und FooFactory sowie IFoo und Foo flogen herum, wenn sie nur eine Foo-Klasse und möglicherweise ein Fooable-Protokoll brauchten.
Um sicherzustellen, dass Sie dies nicht tun, müssen Sie die Unterschiede in der Sprache wirklich verstehen. Beispielsweise benötigen Sie die abstrakte Factory und die obigen Factory-Klassen nicht, da Objective-C-Klassenmethoden genauso dynamisch wie Instanzmethoden abgesetzt 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 Kakaowanzen 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. beim Beenden der App).
Wenn Sie Zeichenfolgen sortieren, die dem Benutzer präsentiert werden sollen, sollten Sie nicht das einfache compare:
Methode. Verwenden Sie stattdessen immer lokalisierte Vergleichsmethoden wie localizedCompare:
oder localizedCaseInsensitiveCompare:
.
Weitere Informationen finden Sie unter Suchen, Vergleichen und Sortieren von Zeichenfolgen .
Versuchen Sie zu vermeiden, was ich jetzt beschlossen habe, Newbiecategoryaholism zu nennen. Wenn Neueinsteiger in Objective-C Kategorien entdecken, werden sie oft wahnsinnig und fügen jeder vorhandenen Klasse nützliche kleine Kategorien hinzu ( "Was? Ich kann eine Methode hinzufügen, um eine Zahl in römische Ziffern in NSNumber umzuwandeln rock on! ").
Mach das nicht.
Ihr Code wird portabler und verständlicher, wenn Sie Dutzende kleiner Kategoriemethoden verwenden, die auf zwei Dutzend Basisklassen verteilt sind.
In den meisten Fällen, in denen Sie der Meinung sind, dass Sie eine Kategoriemethode benötigen, um Code zu optimieren, werden Sie feststellen, dass Sie die Methode nie wieder verwenden.
Es gibt auch andere Gefahren, es sei denn, Sie geben Ihrer Kategoriemethode einen Namensraum (und wer außer dem völlig verrückten Ddribin ist das?), Es besteht die Möglichkeit, dass Apple, ein Plugin oder etwas anderes, das in Ihrem Adressraum ausgeführt wird, dieselbe Kategorie definieren Methode mit dem gleichen Namen mit einer etwas anderen Nebenwirkung ....
OKAY. Nachdem Sie gewarnt wurden, ignorieren Sie das Feld "Tun Sie diesen Teil nicht". Aber übe extreme Zurückhaltung aus.
Widerstehen Sie der Unterteilung der Welt. In Cocoa erfolgt eine Menge durch Delegieren und Verwenden der zugrunde liegenden Laufzeit, die in anderen Frameworks durch Unterklassen erfolgt.
Zum Beispiel verwenden Sie in Java anonyme *Listener
Unterklassen viel und in .NET verwenden Sie Ihre EventArgs
Unterklassen viel. In Cocoa tun Sie dies auch nicht - stattdessen wird die Zielaktion verwendet.
In der Regel sollten Sie für alle Ihre Eigenschaften die Funktion für deklarierte Objective-C 2.0-Eigenschaften verwenden. Wenn sie nicht öffentlich sind, fügen Sie sie einer Klassenerweiterung hinzu. Die Verwendung deklarierter Eigenschaften macht die Speicherverwaltungssemantik sofort klar und erleichtert Ihnen die Überprüfung Ihrer Freigabemethode. Wenn Sie Ihre Eigenschaftsdeklarationen zusammenfassen, können Sie sie schnell scannen und mit der Implementierung Ihrer Freigabemethode vergleichen.
Sie sollten gründlich nachdenken, bevor Sie Eigenschaften nicht als "nichtatomar" markieren. Wie in The Objective C Programming Language Guide angegeben, sind die Eigenschaften standardmäßig atomar und verursachen erheblichen Overhead. Darüber hinaus ist Ihre Anwendung nicht threadsicher, wenn Sie einfach alle Ihre Eigenschaften atomar machen. Beachten Sie auch, dass Sie, wenn Sie nicht 'nonatomic' angeben und Ihre eigenen Accessor-Methoden implementieren (anstatt sie zu synthetisieren), diese auf atomare Weise implementieren müssen.
Wie diese Frage feststellt, sind Nachrichten an nil
in Objective-C gültig. Dies ist zwar häufig ein Vorteil, der zu einem saubereren und natürlicheren Code führt, aber die Funktion kann gelegentlich zu merkwürdigen und schwer auffindbaren Fehlern führen, wenn Sie einen nil
-Wert erhalten, den Sie nicht erwartet haben es.
Verwenden Sie NSAssert und Freunde. Ich benutze immer nil als gültiges Objekt ... besonders das Senden von Nachrichten an nil ist in Obj-C absolut gültig. Wenn ich jedoch wirklich den Status einer Variablen überprüfen möchte, verwende ich NSAssert und NSParameterAssert, um Probleme auf einfache Weise aufzuspüren.
Einfach, aber oft vergessen. Laut spezifikation:
Im Allgemeinen müssen Methoden in verschiedenen Klassen, die denselben Selektor (denselben Namen) haben, denselben Rückgabe- und Argumenttyp haben. Diese Einschränkung wird vom Compiler festgelegt, um eine dynamische Bindung zu ermöglichen.
in diesem Fall wird davon ausgegangen, dass alle gleichnamigen Selektoren auch wenn sie in verschiedenen Klassen enthalten sind 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 "Instrumente" Speicherlecks suchen und nachverfolgen. Nachdem Sie Ihr Programm in Xcode erstellt haben, wählen Sie "Ausführen"> "Mit Leistungstool starten"> "Lecks".
Auch wenn Ihre App keine Lecks aufweist, können Sie Objekte zu lange aufbewahren. In Instruments können Sie hierfür das ObjectAlloc-Instrument verwenden. Wählen Sie das ObjectAlloc-Instrument in Ihrem Instrumentendokument aus und rufen Sie das Instrumentendetail auf (falls es nicht bereits angezeigt wird), indem Sie Ansicht> Detail auswählen (es sollte ein Häkchen daneben haben). 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, wird durch Auswahl des ObjectAlloc-Tools in der Spalte "# Net" angezeigt, 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 zum Beispiel keine Fenster auf dem Bildschirm haben und Verweise auf ein noch lebendes NSWindow sehen, haben Sie es möglicherweise nicht in Ihrem Code veröffentlicht.
Aufräumen in Dealloc.
Dies ist eines der am leichtesten zu vergessenden Dinge. bei Codierung mit 150 Meilen pro Stunde. Bereinigen Sie immer, immer, immer Ihre Attribute/Mitgliedsvariablen in Dealloc.
Ich verwende gerne Objc 2-Attribute - mit die neue Punktnotation - damit die Bereinigung schmerzlos wird. Oft so einfach wie:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
Dies erledigt die Freigabe für Sie und setzt das Attribut auf NULL (was ich für defensives Programmieren halte - falls eine andere Methode weiter unten in Dealloc erneut auf die Member-Variable zugreift - selten, aber könnte passieren).
Mit der in 10.5 aktivierten GC ist dies nicht mehr so wichtig. Möglicherweise müssen Sie jedoch noch andere Ressourcen bereinigen, die Sie erstellt haben. Sie können dies stattdessen mit der Finalize-Methode tun.
Alle diese Kommentare sind großartig, aber ich bin wirklich überrascht, dass niemand sie erwähnt hat Googles Objective-C Style Guide das wurde vor einiger Zeit veröffentlicht. Ich denke, sie haben einen sehr gründlichen Job gemacht.
Auch semi-verwandtes Thema (mit Platz für mehr Antworten!):
Was sind diese kleinen Xcode-Tipps und Tricks, von denen Sie sich vor 2 Jahren gewünscht haben? .
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 für Anfänger naheliegende: Verwenden Sie die automatische Einrückung von Xcode für Ihren Code. Auch 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 innerhalb dieses Blocks erneut einzurücken.
Xcode analysiert diesen Abschnitt und rückt ihn anhand von Klammern, Schleifen usw. ein. Dies ist weitaus effizienter, als die Leertaste oder die Tabulatortaste für jede einzelne Zeile zu drücken.
Variablen und Eigenschaften
1/Halten Sie Ihre Header sauber und verbergen Sie die Implementierung
Fügen Sie keine Instanzvariablen in Ihren Header ein. Private Variablen werden als Eigenschaften in die Klassenfortsetzung eingefügt. Öffentliche Variablen werden in Ihrem Header als öffentliche Eigenschaften deklariert. Wenn es nur gelesen werden soll, deklarieren Sie es als readonly und überschreiben es als readwrite in class continuation. 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 abfangen, die dadurch verursacht werden, dass Sie "Selbst" vergessen. bei der Zuweisung der Immobilie. Grund 2: Aufgrund meiner Experimente hat Leak Analyzer in Instruments Probleme, undichte Stellen mit dem Standardnamen zu erkennen.
3/Verwenden Sie Retain oder Release niemals direkt auf Immobilien (oder nur in sehr außergewöhnlichen Situationen). Weisen Sie ihnen in Ihrem Dealloc einfach eine Null zu. Retain-Eigenschaften sollen Retain/Release von sich aus handhaben. Sie wissen nie, ob ein Setter beispielsweise keine Beobachter hinzufügt oder entfernt. Sie sollten die Variable direkt nur in ihrem Setter und Getter verwenden.
Views
1/Fügen Sie nach Möglichkeit jede Ansichtsdefinition in eine XIB ein (die Ausnahme sind normalerweise dynamische Inhalte und Ebeneneinstellungen). Das spart Zeit (es ist einfacher als das Schreiben von Code), ist einfach zu ändern und hält Ihren Code sauber.
2/Versuchen Sie nicht, die Ansichten zu optimieren, indem Sie die Anzahl der Ansichten verringern. Erstellen Sie UIImageView nicht in Ihrem Code anstelle von xib, nur weil Sie ihm Unteransichten hinzufügen möchten. Verwenden Sie stattdessen UIImageView als Hintergrund. Das Ansichts-Framework 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 aufgerufen.
Speicher
1/Objekte automatisch freigeben, wenn Sie sie erstellen. Viele Fehler treten auf, 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. wenn Sie auf einen Runloop warten und Ihr Objekt nicht zu früh automatisch freigegeben werden soll.
2/Auch wenn Sie Authomatic Reference Counting verwenden, müssen Sie die Funktionsweise von Retain-Release-Methoden genau verstehen. Die manuelle Verwendung der Retain-Freigabe ist nicht komplizierter als die Verwendung von ARC. In beiden Fällen müssen Leckagen und Retain-Zyklen behoben werden. Ziehen Sie in Betracht, Retain-Release manuell für große Projekte oder komplizierte Objekthierarchien zu verwenden.
Kommentare
1/Machen Sie Ihren Code automatisch dokumentiert. Jeder Variablenname und Methodenname sollte angeben, was er tut. Wenn der Code korrekt geschrieben ist (Sie müssen viel üben), benötigen Sie keine Codekommentare (nicht das Gleiche wie Dokumentationskommentare). Algorithmen können kompliziert sein, aber der Code sollte immer einfach sein.
2/Manchmal brauchst du einen Kommentar. Normalerweise, um ein nicht offensichtliches Code-Verhalten oder einen nicht offensichtlichen Hack zu beschreiben. Wenn Sie der Meinung sind, dass Sie einen Kommentar schreiben müssen, versuchen Sie zunächst, den Code einfacher und ohne die Notwendigkeit von Kommentaren umzuschreiben.
Einrückung
1/Erhöhen Sie die Einrückung nicht zu stark. Der größte Teil Ihres Methodencodes sollte auf der 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 einer separaten Methode zu platzieren. 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;
C-Code verstehen, hauptsächlich C-Strukturen
Beachten Sie, dass Obj-C nur eine leichte OOP= Ebene über 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;
nd viele mehr
Verwalten Sie Ihr eigenes Kodierungsnormen-Dokument und aktualisieren Sie es regelmäßig. Versuchen Sie, aus Ihren Fehlern zu lernen. Verstehen Sie, warum ein Fehler verursacht 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 standardmäßige Einrückungen, Leerzeichen und Leerzeichen Linien an den richtigen Stellen usw.
Aktivieren Sie alle GCC-Warnungen und deaktivieren Sie die Warnungen, die regelmäßig von Apple-Headern 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 mit jedem Build aus.
Ich weiß, dass ich das übersehen habe, als ich zum ersten Mal mit Cocoa-Programmierung angefangen habe.
Stellen Sie sicher, dass Sie die Verantwortlichkeiten für die Speicherverwaltung in Bezug auf NIB-Dateien kennen. Sie sind dafür verantwortlich, die Objekte der obersten Ebene in jeder von Ihnen geladenen NIB-Datei freizugeben. Lesen Sie Apples Dokumentation zum Thema.
Sei mehr funktional.
Objective-C ist eine objektorientierte Sprache, die sich jedoch des funktionalen Stils des Cocoa-Frameworks bewusst ist und in vielen Fällen einen funktionalen Stil aufweist.
Es gibt eine Trennung der Veränderbarkeit. Verwenden Sie unveränderliche Klassen als primäres und veränderliches Objekt als sekundäres. Verwenden Sie beispielsweise in erster Linie NSArray und nur dann NSMutableArray, wenn Sie dies benötigen.
Es gibt reine Funktionen. Nicht so viele, viele Framework-APIs sind wie reine Funktionen konzipiert. Schauen Sie sich Funktionen wie CGRectMake()
oder CGAffineTransformMake()
an. Offensichtlich sieht die Zeigerform effizienter aus. Indirektes Argumentieren mit Zeigern kann jedoch nicht nebenwirkungsfrei sein. Konstruieren Sie Strukturen so weit wie möglich. Trenne gerade Zustandsobjekte. Verwenden -copy
anstatt -retain
, wenn ein Wert an ein anderes Objekt übergeben wird. Weil der gemeinsame Zustand die Mutation zu einem Wert in einem anderen Objekt stillschweigend beeinflussen kann. Kann also nicht nebenwirkungsfrei sein. Wenn Sie einen Wert von external from object haben, kopieren Sie ihn. Daher ist es auch wichtig, den gemeinsamen Status so minimal wie möglich zu gestalten.
Haben Sie jedoch keine Angst, auch unreine Funktionen zu verwenden.
Es gibt eine faule Bewertung. Sehen Sie etwas wie -[UIViewController view]
Eigentum. Die Ansicht wird beim Erstellen des Objekts nicht erstellt. Es wird erstellt, wenn der Aufrufer die Eigenschaft view
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 Evaluierung nicht kennen, ist es nicht einfach, deren Verhalten zu verstehen.
Es gibt Schließung. Verwenden Sie so oft wie möglich C-Blöcke. Dies wird Ihr Leben erheblich vereinfachen. Aber lesen Sie noch einmal über Block-Memory-Management, bevor Sie es verwenden.
Es gibt semi-auto GC. NSAutoreleasePool. Verwenden -autorelease
primär. Gebrauchsanleitung -retain/-release
sekundär, wenn Sie wirklich brauchen. (zB Speicheroptimierung, explizites Löschen von Ressourcen)
In den von Apple bereitgestellten Beispielen wurde der App-Delegierte wie ein globaler Datenspeicher behandelt, eine Art Datenmanager. Das ist falsch. Erstellen Sie einen Singleton und instanziieren Sie ihn möglicherweise im App-Delegaten. Verwenden Sie den App-Delegaten jedoch nicht als mehr als nur Ereignisbehandlung auf Anwendungsebene. Ich stimme den Empfehlungen in diesem Blogeintrag von Herzen zu. Dieser Thread hat mich darauf hingewiesen.
Geben Sie nur eine Eigenschaft in Freigabe -Methode frei. Wenn Sie Speicher freigeben möchten, den die Eigenschaft enthält, setzen Sie ihn einfach auf nil:
self.<property> = nil;
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass