wake-up-neo.com

Welche bewährten Methoden verwenden Sie beim Schreiben von Objective-C und Cocoa?

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).

346
pixel

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

Verwenden Sie keine unbekannten Zeichenfolgen als Formatzeichenfolgen

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);
110
mmalc

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:

  • Nicht deklarieren 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 .
  • Nenne keinen Getter -getSomething; der richtige Kakao-Name ist nur -something.
  • Benenne keinen Setter -something:; es sollte sein -setSomething:
  • Der Methodenname ist mit den Argumenten durchsetzt und enthält Doppelpunkte. es ist -[NSObject performSelector:withObject:], nicht NSObject::performSelector.
  • Verwenden Sie Inter-Caps (CamelCase) in Methodennamen, Parametern, Variablen, Klassennamen usw. anstelle von Unterstrichen.
  • Klassennamen beginnen mit einem Großbuchstaben, Variablennamen und Methodennamen mit Kleinbuchstaben.

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.

108
Chris Hanson

IBOutlets

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.

107
mmalc

Verwenden Sie den LLVM/Clang Static Analyzer

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:

  1. Laden Sie die neueste Version von diese Seite herunter.
  2. Von der Befehlszeile aus cd in Ihr Projektverzeichnis.
  3. Ausführen 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.

98
mmalc

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;
95
schwa

@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.

87
schwa

Vermeiden Sie Autorelease

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 .

75
mmalc

Einige davon wurden bereits erwähnt, aber hier ist, was ich auf den ersten Blick denken kann:

  • Befolgen Sie die KVO-Benennungsregeln. Auch wenn Sie KVO jetzt nicht verwenden, ist es meiner Erfahrung nach in der Zukunft häufig noch von Vorteil. Und wenn Sie KVO oder Bindungen verwenden, müssen Sie wissen, dass die Dinge so funktionieren, wie sie sollen. Dies umfasst nicht nur Zugriffsmethoden und Instanzvariablen, sondern auch zu viele Beziehungen, Validierung, automatische Benachrichtigung abhängiger Schlüssel usw.
  • Private Methoden in eine Kategorie einordnen. Nicht nur die Schnittstelle, sondern auch die Implementierung. Es ist gut, konzeptionell eine gewisse Distanz zwischen privaten und nicht-privaten Methoden zu haben. Ich füge alles in meine .m-Datei ein.
  • Fügen Sie die Hintergrund-Thread-Methoden in eine Kategorie ein. Wie oben. Ich habe festgestellt, dass es gut ist, eine klare konzeptionelle Barriere beizubehalten, wenn Sie darüber nachdenken, was sich auf dem Haupt-Thread befindet und was nicht.
  • Verwenden Sie #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.
  • Private Methoden und ivars mit _ voranstellen. Mir gefällt das Aussehen und ich verwende seltener einen ivar, wenn ich versehentlich eine Immobilie meine.
  • Verwenden Sie in init & dealloc keine mutator-Methoden/-Eigenschaften. Es ist noch nie etwas Schlimmes passiert, aber ich kann die Logik erkennen, wenn Sie die Methode ändern, um etwas zu tun, das von der abhängt Zustand Ihres Objekts.
  • Fügen Sie IBOutlets in Eigenschaften ein. Ich habe gerade hier gelesen, aber ich werde damit beginnen. Ungeachtet der Vorteile für das Gedächtnis scheint es (zumindest für mich) stilistisch besser zu sein.
  • Vermeiden Sie es, Code zu schreiben, den Sie nicht unbedingt benötigen. Dies deckt wirklich eine Menge Dinge ab, wie das Erstellen von Ivars, wenn ein #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.
  • Beenden Sie, was Sie beginnen. Wenn Sie eine Menge halbfertigen, fehlerhaften Codes haben, ist dies der schnellste Weg, ein Projekt zu töten, das tot ist. Wenn Sie eine Stub-Methode benötigen, die in Ordnung ist, geben Sie sie einfach an, indem Sie NSLog( @"stub" ) einfügen, oder Sie möchten den Überblick behalten.
70

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.

56
Chris Hanson

Goldene Regel: Wenn Sie alloc dann Sie release!

UPDATE: Es sei denn, Sie verwenden ARC

55
JamesSugrue

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.

55
Chris Hanson

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).

50
mj1531

Sortieren Sie die Zeichenfolgen nach Belieben des Benutzers

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 .

38
mmalc

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.

38
schwa

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.

37
Chris Hanson

Deklarierte Eigenschaften

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.

31
mmalc

Denken Sie über Nullwerte nach

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.

26
mmalc

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.

26
NikWest

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;
}   
23
Özgür

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.

22
mj1531

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.

21
schwa

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.

17
slf
15
schwa

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.

13
mj1531

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.

12
iwasrobbed

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.

10
Sulthan

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.

10
oefe

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.

10
mj1531

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.

  1. 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.

  2. 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.

  1. 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.

  2. 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.

  3. 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)

9
Eonil

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.

8
bbrown

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;
4
Tuan Nguyen
#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass
0
Nirmit Pathak