Domanda

So di HIG (che è abbastanza utile!), ma quali pratiche di programmazione usi quando scrivi Objective-C, e più specificamente quando usi Cocoa (o CocoaTouch).

È stato utile?

Soluzione

Ci sono alcune cose che ho iniziato a fare che non credo siano standard:

1) Con l'avvento delle proprietà, non uso più " _ " per aggiungere il prefisso "privato" variabili di classe. Dopotutto, se una variabile è accessibile da altre classi non dovrebbe esserci una proprietà per essa? Non ho sempre apprezzato il " _ " prefisso per rendere il codice più brutto e ora posso lasciarlo fuori.

2) A proposito di cose private, preferisco inserire le definizioni dei metodi privati ??all'interno del file .m in un'estensione di classe in questo modo:

#import "MyClass.h"

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

@implementation MyClass

Perché ingombrare il file .h con cose che agli estranei non dovrebbe interessare? Empty () funziona per le categorie private nel file .m e genera avvisi di compilazione se non si implementano i metodi dichiarati.

3) Ho iniziato a mettere dealloc nella parte superiore del file .m, appena sotto le direttive @synthesize. Ciò che dovresti collocare non dovrebbe essere in cima all'elenco delle cose a cui vuoi pensare in una classe? Ciò è particolarmente vero in un ambiente come l'iPhone.

3.5) Nelle celle della tabella, rendere opaco ogni elemento (inclusa la cella stessa) per le prestazioni. Ciò significa impostare il colore di sfondo appropriato in tutto.

3.6) Quando si utilizza un NSURLConnection, di norma si consiglia di implementare il metodo delegato:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

Trovo che la maggior parte delle chiamate Web siano molto singolari ed è più un'eccezione rispetto alla regola che vorrete avere le risposte memorizzate nella cache, specialmente per le chiamate ai servizi web. L'implementazione del metodo come mostrato disabilita la memorizzazione nella cache delle risposte.

Interessanti anche alcuni buoni suggerimenti specifici per iPhone di Joseph Mattiello (ricevuti in una mailing list per iPhone). Ce ne sono altri, ma questi erano i più generalmente utili che ho pensato (nota che alcuni bit sono stati leggermente modificati dall'originale per includere i dettagli offerti nelle risposte):

4) Utilizzare la doppia precisione solo se necessario, ad esempio quando si lavora con CoreLocation. Assicurati di terminare le tue costanti in 'f' per fare in modo che gcc le memorizzi come float.

float val = someFloat * 2.2f;

Questo è importante soprattutto quando someFloat può effettivamente essere un doppio, non hai bisogno della matematica in modalità mista, poiché stai perdendo precisione in 'val' sullo spazio di archiviazione. Mentre i numeri a virgola mobile sono supportati nell'hardware su iPhone, potrebbe essere necessario più tempo per eseguire l'aritmetica a doppia precisione rispetto alla precisione singola. Riferimenti:

Sui telefoni più vecchi si suppone che i calcoli funzionino alla stessa velocità ma si possono avere più componenti di precisione singoli nei registri rispetto ai doppi, quindi per molti calcoli la precisione singola finirà per essere più veloce.

5) Imposta le tue proprietà come nonatomic . Sono atomic per impostazione predefinita e dopo la sintesi, il codice semaforo verrà creato per prevenire problemi multi-threading. Il 99% di voi probabilmente non deve preoccuparsi di questo e il codice è molto meno gonfio e più efficiente in termini di memoria quando impostato su non anatomico.

6) SQLite può essere un modo molto, molto veloce per memorizzare nella cache set di dati di grandi dimensioni. Un'applicazione mappa, ad esempio, può memorizzare nella cache i suoi riquadri in file SQLite. La parte più costosa è l'I / O del disco. Evita molte piccole scritture inviando BEGIN; e COMMIT; tra blocchi di grandi dimensioni. Ad esempio, utilizziamo un timer di 2 secondi che si reimposta su ogni nuovo invio. Quando scade, inviamo COMMIT; , che fa sì che tutte le tue scritture vadano in un grosso blocco. SQLite memorizza i dati delle transazioni su disco e facendo questo inizio / fine il wrapping evita la creazione di molti file di transazione, raggruppando tutte le transazioni in un unico file.

Inoltre, SQL bloccherà la tua GUI se si trova sul tuo thread principale. Se hai una query molto lunga, è una buona idea archiviare le tue query come oggetti statici ed eseguire il tuo SQL su un thread separato. Assicurati di racchiudere tutto ciò che modifica il database per le stringhe di query nei blocchi @synchronize () {} . Per domande brevi, lascia semplicemente le cose sul thread principale per una maggiore comodità.

Sono disponibili altri suggerimenti per l'ottimizzazione di SQLite, sebbene il documento appaia obsoleto molti dei punti probabilmente sono ancora validi;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ .html

Altri suggerimenti

Non utilizzare stringhe sconosciute come stringhe di formato

Quando i metodi o le funzioni accettano un argomento stringa di formato, è necessario assicurarsi di avere il controllo sul contenuto della stringa di formato.

Ad esempio, quando si registrano le stringhe, si è tentati di passare la variabile stringa come unico argomento a NSLog :

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

Il problema è che la stringa può contenere caratteri interpretati come stringhe di formato. Ciò può causare output errati, arresti anomali e problemi di sicurezza. Invece, è necessario sostituire la variabile stringa in una stringa di formato:

    NSLog(@"%@", aString);

Usa convenzioni e terminologia standard per la denominazione e la formattazione del cacao piuttosto che qualsiasi cosa a cui sei abituato da un altro ambiente. Ci sono ci sono molti sviluppatori di Cocoa là fuori, e quando un altro di loro inizia a lavorare con il tuo codice, sarà molto più accessibile se sembra e si sente simile ad altri codici Cocoa.

Esempi di cosa fare e cosa non fare:

  • Non dichiarare id m_something; nell'interfaccia di un oggetto e chiamarlo variabile membro o campo ; usa qualcosa o _something per il suo nome e chiamalo una variabile di istanza .
  • Non nominare un getter -getSomething ; il nome proprio di Cocoa è solo -something .
  • Non nominare un setter -something: ; dovrebbe essere -setSomething:
  • Il nome del metodo è intervallato dagli argomenti e include due punti; è - [NSObject performSelector: withObject:] , non NSObject :: performSelector .
  • Usa le maiuscole (CamelCase) nei nomi dei metodi, parametri, variabili, nomi delle classi, ecc. anziché nelle barre di sottolineatura (caratteri di sottolineatura).
  • I nomi delle classi iniziano con una lettera maiuscola, variabili e metodi con lettere minuscole.

Qualunque altra cosa tu faccia, non usa la notazione ungherese in stile Win16 / Win32. Perfino Microsoft ha rinunciato a questo con il passaggio alla piattaforma .NET.

IBOutlets

Storicamente, la gestione della memoria delle prese è stata scarsa. La migliore pratica corrente è dichiarare gli sbocchi come proprietà:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

L'uso delle proprietà rende chiara la semantica della gestione della memoria; fornisce anche un modello coerente se usi la sintesi delle variabili di istanza.

Utilizza l'analizzatore statico LLVM / Clang

NOTA: in Xcode 4 questo è ora incorporato nell'IDE.

Usi Clang Static Analyzer per - non sorprende - analizzare la tua C e il tuo obiettivo -Codice C (non ancora C ++) su Mac OS X 10.5. È banale da installare e utilizzare:

  1. Scarica l'ultima versione da questa pagina .
  2. Dalla riga di comando, cd nella directory del progetto.
  3. Esegui scan-build -k -V xcodebuild .

(Ci sono alcuni vincoli aggiuntivi ecc., in particolare dovresti analizzare un progetto nella sua configurazione "Debug" - vedi http://clang.llvm.org/StaticAnalysisUsage.html per i dettagli - ma è più o meno ciò a cui si riduce.)

L'analizzatore produce quindi una serie di pagine Web che mostrano la probabile gestione della memoria e altri problemi di base che il compilatore non è in grado di rilevare.

Questo è sottile ma utile. Se ti stai passando come delegato a un altro oggetto, reimposta il delegato di quell'oggetto prima di dealloc .

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

In questo modo ti stai assicurando che non verranno inviati più metodi delegati. Mentre stai per dealloc e sparire nell'etere, vuoi assicurarti che nulla possa inviarti altri messaggi per caso. Ricorda self.someObject potrebbe essere trattenuto da un altro oggetto (potrebbe essere un singleton o nel pool di rilascio automatico o qualsiasi altra cosa) e fino a quando non lo dirai " smetti di inviarmi messaggi! & Quot ;, pensa che stai per essere l'oggetto dealloced è un gioco leale.

Entrare in questa abitudine ti salverà da molti strani incidenti che sono un dolore da debug.

Lo stesso principio si applica all'osservazione dei valori chiave e anche alle notifiche NSN.

Modifica:

Ancora più difensivo, cambia:

self.someObject.delegate = NULL;

in:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

@kendell

Invece di:

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

Usa:

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

Novità in Objective-C 2.0.

Le estensioni di classe sono descritte nel riferimento Apple Objective-C 2.0.

" Le estensioni di classe ti consentono di dichiarare un'API aggiuntiva richiesta per una classe in posizioni diverse dal blocco @interface della classe primaria "

Quindi fanno parte della classe reale - e NON una categoria (privata) oltre alla classe. Differenza sottile ma importante.

Evita il rilascio automatico

Poiché in genere (1) non si ha il controllo diretto sulla loro durata, gli oggetti rilasciati automaticamente possono persistere per un tempo relativamente lungo e aumentare inutilmente l'impronta di memoria dell'applicazione. Mentre sul desktop questo può avere poche conseguenze, su piattaforme più vincolate questo può essere un problema significativo. Su tutte le piattaforme, quindi, e specialmente su piattaforme più vincolate, si considera la migliore pratica per evitare l'uso di metodi che porterebbero a oggetti rilasciati automaticamente e invece si è incoraggiati a usare il modello alloc / init.

Quindi, piuttosto che:

aVariable = [AClass convenienceMethod];

dove possibile, dovresti invece usare:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

Quando scrivi i tuoi metodi che restituiscono un oggetto appena creato, puoi trarre vantaggio da convenzione di denominazione di Cocoa per segnalare al destinatario che deve essere rilasciato anteponendo il nome del metodo con " new ".

Pertanto, anziché:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

potresti scrivere:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

Poiché il nome del metodo inizia con " nuovo " ;, i consumatori dell'API sanno di essere responsabili del rilascio dell'oggetto ricevuto (vedere, ad esempio, NSObjectController's newObject method ).

(1) Puoi prendere il controllo usando i tuoi pool di autorelease locali. Per ulteriori informazioni, consulta Pool di autorelease .

Alcuni di questi sono già stati menzionati, ma ecco cosa posso pensare dalla cima della mia testa:

  • Segui le regole di denominazione KVO. Anche se non usi KVO ora, nella mia esperienza spesso è ancora utile in futuro. E se stai usando KVO o attacchi, devi sapere che le cose funzioneranno come dovrebbero. Questo riguarda non solo i metodi di accesso e le variabili di istanza, ma anche troppe relazioni, convalida, chiavi dipendenti con notifica automatica e così via.
  • Metti i metodi privati ??in una categoria. Non solo l'interfaccia, ma anche l'implementazione. È bene avere una certa distanza concettualmente tra metodi privati ??e non privati. Includo tutto nel mio file .m.
  • Inserisci i metodi di thread in background in una categoria. Come sopra. Ho trovato bello mantenere una chiara barriera concettuale quando stai pensando a cosa c'è nel thread principale e cosa no.
  • Usa #pragma mark [sezione] . Di solito raggruppo con i miei metodi, le sostituzioni di ogni sottoclasse e qualsiasi informazione o protocollo formale. Questo rende molto più semplice passare esattamente a quello che sto cercando. Sullo stesso argomento, raggruppa metodi simili (come i metodi delegati di una vista tabella), non incollarli ovunque.
  • Prefisso metodi privati ??e amp; ivars con _. Mi piace il modo in cui appare e ho meno probabilità di usare un ivar quando intendo una proprietà per caso.
  • Non utilizzare metodi / proprietà mutatori in init & amp; dealloc. Non ho mai avuto niente di grave a causa di ciò, ma posso vedere la logica se cambi il metodo per fare qualcosa che dipende dallo stato del tuo oggetto.
  • Metti IBOutlet nelle proprietà. In realtà ho appena letto questo qui, ma inizierò a farlo. Indipendentemente da eventuali benefici della memoria, sembra stilisticamente migliore (almeno per me).
  • Evita di scrivere codice di cui non hai assolutamente bisogno. Questo copre davvero molte cose, come fare gli ivar quando lo farà un #define o invece memorizzare nella cache un array di ordinarlo ogni volta che sono necessari i dati. C'è molto che potrei dire al riguardo, ma la linea di fondo è non scrivere codice fino a quando non ne hai bisogno, o il profiler te lo dice. Rende le cose molto più facili da mantenere a lungo termine.
  • Termina ciò che inizi. Avere un sacco di codice buggy a metà è il modo più veloce per uccidere un progetto morto. Se hai bisogno di un metodo stub che va bene, basta indicarlo inserendo NSLog (@ " stub ") , o comunque vuoi tenere traccia delle cose.

Scrivi unit test. Puoi testare un lotto di cose in Cocoa che potrebbero essere più difficili in altri framework. Ad esempio, con il codice UI, puoi generalmente verificare che le cose siano connesse come dovrebbero e confidare che funzioneranno una volta utilizzate. E puoi impostare state & amp; invocare facilmente metodi delegati per testarli.

Inoltre non hai visibilità del metodo pubblico vs. protetto vs. privato che ti impedisce di scrivere test per i tuoi interni.

Regola d'oro: se allocare allora rilasci !

AGGIORNAMENTO: A meno che tu non stia usando ARC

Non scrivere Objective-C come se fosse Java / C # / C ++ / ecc.

Una volta ho visto un team abituato a scrivere applicazioni web Java EE tentare di scrivere un'applicazione desktop Cocoa. Come se fosse un'applicazione web Java EE. C'erano un sacco di AbstractFooFactory e FooFactory e IFoo e Foo che volavano in giro quando tutto ciò di cui avevano veramente bisogno era una classe Foo e forse un protocollo Fooable.

Parte della garanzia di non farlo consiste nel comprendere veramente le differenze nella lingua. Ad esempio, non sono necessarie le classi factory e factory astratte sopra perché i metodi di classe Objective-C vengono inviati in modo dinamico come i metodi di istanza e possono essere sovrascritti in sottoclassi.

Assicurati di aggiungere la pagina Debugging Magic ai preferiti. Questa dovrebbe essere la tua prima fermata quando sbatti la testa contro un muro mentre cerchi di trovare la fonte di un bug di Cocoa.

Ad esempio, ti spiegherà come trovare il metodo in cui hai allocato per la prima volta la memoria che in seguito causa arresti anomali (come durante la chiusura dell'app).

Ordina le stringhe come desidera l'utente

Quando ordini le stringhe da presentare all'utente, non dovresti usare il semplice metodo compare: . Invece, dovresti sempre usare metodi di confronto localizzati come localizedCompare: o localizedCaseInsensitiveCompare: .

Per maggiori dettagli, vedi Ricerca, confronto e ordinamento stringhe .

Cerca di evitare ciò che ora ho deciso di chiamare Newbiecategoryaholism. Quando i nuovi arrivati ??in Objective-C scoprono le categorie, spesso si scatenano, aggiungendo utili piccole categorie a ogni classe esistente ( " What? Posso aggiungere un metodo per convertire un numero in numeri romani in NSNumber rock su! & Quot; ).

Non farlo.

Il tuo codice sarà più portatile e più facile da capire senza dozzine di metodi di piccole categorie sparsi su due dozzine di classi di base.

Il più delle volte quando pensi davvero di aver bisogno di un metodo di categoria per semplificare un po 'di codice, scoprirai che non finirai mai per riutilizzare il metodo.

Ci sono anche altri pericoli, a meno che tu non stia indicando i metodi della tua categoria (e chi oltre al follemente ddribin è?) c'è la possibilità che anche Apple, un plugin o qualcos'altro in esecuzione nel tuo spazio degli indirizzi definisca lo stesso metodo di categoria con lo stesso nome con un effetto collaterale leggermente diverso ....

OK. Ora che sei stato avvisato, ignora il " non fare questa parte " ;. Ma esercita estrema moderazione.

Resistere alla sottoclasse del mondo. In Cocoa si fa molto attraverso la delega e l'uso del runtime sottostante che in altri framework avviene tramite la sottoclasse.

Ad esempio, in Java usi molto spesso le sottoclassi * Listener anonime e in .NET usi molto le tue sottoclassi EventArgs . In Cocoa, non lo fai neanche tu: al suo posto viene utilizzata l'azione-bersaglio.

Proprietà dichiarate

In genere è necessario utilizzare la funzione Proprietà dichiarate Objective-C 2.0 per tutte le proprietà. Se non sono pubblici, aggiungili in un'estensione di classe. L'uso delle proprietà dichiarate rende immediatamente chiara la semantica della gestione della memoria e semplifica la verifica del metodo dealloc: se raggruppate le dichiarazioni delle proprietà, potete scansionarle rapidamente e confrontarle con l'implementazione del metodo dealloc.

Dovresti pensare intensamente prima di non contrassegnare le proprietà come "non anatomiche". Come La Guida al linguaggio di programmazione dell'obiettivo C , le proprietà sono atomico per impostazione predefinita e comporta un notevole sovraccarico. Inoltre, semplicemente rendere atomiche tutte le proprietà non rende l'applicazione thread-safe. Si noti inoltre, ovviamente, che se non si specifica "nonatomico" e si implementano i propri metodi di accesso (piuttosto che sintetizzarli), è necessario implementarli in modo atomico.

Pensa a valori nulli

Come questa domanda osserva, i messaggi a nil sono validi in Objective-C. Sebbene questo sia spesso un vantaggio - portando a un codice più pulito e più naturale - la funzione può occasionalmente portare a bug particolari e difficili da rintracciare se ottieni un valore nil quando non eri ' aspettarselo.

Usa NSAssert e i tuoi amici. Uso sempre zero come oggetto valido ... soprattutto l'invio di messaggi a zero è perfettamente valido in Obj-C. Tuttavia, se voglio davvero accertarmi dello stato di una variabile, utilizzo NSAssert e NSParameterAssert, che aiutano a rintracciare facilmente i problemi.

Semplice ma spesso dimenticato. Secondo le specifiche:

  

In generale, metodi in diversi   classi che hanno lo stesso selettore   (lo stesso nome) deve anche condividere il file   stessi tipi di ritorno e argomento. Questo   il vincolo è imposto dal compilatore   per consentire l'associazione dinamica.

nel qual caso tutti i selettori con lo stesso nome, anche se in classi diverse , saranno considerati come aventi identici tipi di ritorno / argomento. Ecco un semplice esempio.

@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;
}   

Se si utilizza Leopard (Mac OS X 10.5) o versioni successive, è possibile utilizzare l'applicazione Instruments per trovare e tenere traccia delle perdite di memoria. Dopo aver creato il tuo programma in Xcode, seleziona Esegui > Inizia con Performance Tool > Perdite.

Anche se l'app non mostra perdite, è possibile che gli oggetti rimangano troppo a lungo. In Instruments, è possibile utilizzare lo strumento ObjectAlloc per questo. Seleziona lo strumento ObjectAlloc nel documento Instruments e visualizza i dettagli dello strumento (se non è già visualizzato) scegliendo Visualizza > Dettaglio (dovrebbe avere un segno di spunta accanto ad esso). Sotto " Durata della allocazione " nei dettagli ObjectAlloc, assicurati di scegliere il pulsante di opzione accanto a " Created & amp; Still Living " ;.

Ora, ogni volta che interrompi la registrazione della tua applicazione, selezionando lo strumento ObjectAlloc ti mostrerà quanti riferimenti ci sono ad ogni oggetto ancora in vita nella tua applicazione in " # Net " colonna. Assicurati di guardare non solo le tue classi, ma anche le classi degli oggetti di livello superiore dei tuoi file NIB. Ad esempio, se non hai finestre sullo schermo e vedi riferimenti a una NSWindow ancora in vita, potresti non averla rilasciata nel tuo codice.

Pulisci in dealloc.

Questa è una delle cose più facili da dimenticare - esp. quando si codifica a 150 miglia all'ora. Pulisci sempre, sempre, sempre i tuoi attributi / variabili membro in dealloc.

Mi piace usare gli attributi Objc 2 - con la nuova notazione punto - quindi questo rende la pulizia indolore. Spesso semplice come:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

Questo si occuperà del rilascio per te e imposterà l'attributo su NULL (che considero la programmazione difensiva - nel caso in cui un altro metodo più in basso nel dealloc acceda nuovamente alla variabile membro - raro ma potrebbe accadere ).

Con GC attivato nella 10.5, questo non è più necessario, ma potresti comunque aver bisogno di ripulire le altre risorse che crei, invece puoi farlo nel metodo finalize.

Tutti questi commenti sono fantastici, ma sono davvero sorpreso che nessuno abbia menzionato di Google Guida allo stile Objective-C che è stata pubblicata qualche tempo fa. Penso che abbiano svolto un lavoro molto approfondito.

Inoltre, argomento semi-correlato (con spazio per più risposte!):

Cosa sono quei piccoli suggerimenti per Xcode e amp; trucchi che vorresti conoscere 2 anni fa? .

Non dimenticare che NSWindowController e NSViewController rilasceranno gli oggetti di livello superiore dei file NIB che governano.

Se carichi manualmente un file NIB, sei responsabile del rilascio degli oggetti di livello superiore di NIB quando hai finito con loro.

Uno piuttosto ovvio per un principiante: usa la funzione di rientro automatico di Xcode per il tuo codice. Anche se stai copiando / incollando da un'altra fonte, una volta incollato il codice, puoi selezionare l'intero blocco di codice, fare clic con il tasto destro su di esso e quindi scegliere l'opzione per rientrare di nuovo tutto all'interno di quel blocco.

Xcode analizzerà effettivamente quella sezione e la indenterà in base a parentesi, loop, ecc. È molto più efficiente che premere la barra spaziatrice o il tasto tab per ogni riga.

So di averlo ignorato quando ho iniziato a programmare Cocoa.

Assicurati di comprendere le responsabilità di gestione della memoria relative ai file NIB. Sei responsabile del rilascio degli oggetti di livello superiore in qualsiasi file NIB che carichi. Leggi Documentazione di Apple sull'argomento.

Attiva tutti gli avvisi GCC, quindi disattiva quelli che sono regolarmente causati dalle intestazioni di Apple per ridurre il rumore.

Esegui spesso anche l'analisi statica di Clang; puoi abilitarlo per tutte le build tramite " Esegui analizzatore statico " costruire impostazione.

Scrivi unit test ed eseguili con ogni build.

Variabili e proprietà

1 / Mantenere pulite le intestazioni, nascondendo l'implementazione
Non includere variabili di istanza nell'intestazione. Le variabili private inseriscono la continuazione della classe come proprietà. Le variabili pubbliche dichiarano come proprietà pubbliche nell'intestazione. Se deve essere solo letto, dichiaralo come di sola lettura e sovrascriverlo come readwrite nella classe di conversione. Fondamentalmente non sto usando affatto variabili, solo proprietà.

2 / Assegna alle tue proprietà un nome variabile non predefinito, ad esempio:


@synthesize property = property_;

Motivo 1: verranno rilevati errori causati dalla dimenticanza di " self. " quando si assegna la proprietà. Motivo 2: dai miei esperimenti, Leak Analyzer in Instruments ha problemi a rilevare la perdita di proprietà con il nome predefinito.

3 / Non utilizzare mai il mantenimento o il rilascio direttamente sulle proprietà (o solo in situazioni molto eccezionali). Nel tuo dealloc basta assegnare loro uno zero. Le proprietà di conservazione devono essere gestite da sole. Non si sa mai se un setter non sta, ad esempio, aggiungendo o rimuovendo osservatori. Dovresti usare la variabile direttamente solo all'interno del suo setter e getter.

Visualizzazioni

1 / Metti ogni definizione di vista in un xib, se puoi (l'eccezione è di solito il contenuto dinamico e le impostazioni del livello). Fa risparmiare tempo (è più facile che scrivere il codice), è facile da cambiare e mantiene pulito il tuo codice.

2 / Non tentare di ottimizzare le visualizzazioni diminuendo il numero di visualizzazioni. Non creare UIImageView nel tuo codice invece di xib solo perché vuoi aggiungere delle subview in esso. Utilizzare invece UIImageView come sfondo. Il framework delle viste può gestire centinaia di visualizzazioni senza problemi.

3 / IBOutlet non devono essere sempre mantenuti (o forti). Nota che la maggior parte dei tuoi IBOutlet fanno parte della tua gerarchia di visualizzazioni e quindi implicitamente mantenuti.

4 / Rilascia tutti gli IBOutlet in viewDidUnload

5 / Call viewDidScarica dal tuo metodo dealloc. Non è implicitamente chiamato.

Memory

1 / Oggetti di rilascio automatico durante la creazione. Molti bug sono causati dallo spostamento della chiamata di rilascio in un ramo if-else o dopo una dichiarazione di ritorno. Il rilascio anziché il rilascio automatico deve essere utilizzato solo in situazioni eccezionali, ad es. quando stai aspettando un runloop e non vuoi che il tuo oggetto venga rilasciato automaticamente troppo presto.

2 / Anche se si utilizza il conteggio dei riferimenti di Authomatic, è necessario comprendere perfettamente il funzionamento dei metodi di conservazione. L'uso manuale della funzione di ritenuta non è più complicato di ARC, in entrambi i casi devi preoccuparti di perdite e cicli di ritenzione. Prendi in considerazione la possibilità di utilizzare la conservazione manuale su grandi progetti o gerarchie di oggetti complicati.

Commenti

1 / Rendi il tuo codice auto documentato. Ogni nome di variabile e nome di metodo dovrebbe dire cosa sta facendo. Se il codice è scritto correttamente (è necessaria molta pratica in questo), non sarà necessario alcun commento sul codice (non uguale ai commenti sulla documentazione). Gli algoritmi possono essere complicati ma il codice dovrebbe essere sempre semplice.

2 / A volte, avrai bisogno di un commento. Di solito per descrivere un comportamento in codice non apparente o hack. Se ritieni di dover scrivere un commento, prova prima a riscrivere il codice per essere più semplice e senza la necessità di commenti.

indentazione

1 / Non aumentare troppo il rientro. La maggior parte del codice del metodo deve essere rientrato a livello di metodo. I blocchi nidificati (if, for etc.) riducono la leggibilità. Se hai tre blocchi nidificati, dovresti provare a mettere i blocchi interni in un metodo separato. Quattro o più blocchi nidificati non devono mai essere utilizzati. Se la maggior parte del codice del metodo è all'interno di un if, annulla la condizione if, esempio:


if (self) {
   //... long initialization code ...
}

return self;


if (!self) {
   return nil;
}

//... long initialization code ...

return self;

Comprendi il codice C, principalmente le strutture C

Nota che Obj-C è solo un livello OOP leggero sul linguaggio C. Dovresti capire come funzionano le strutture di codice di base in C (enumerazioni, strutture, matrici, puntatori ecc.). Esempio:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

è uguale a:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

E molti altri

Gestisci il tuo documento sugli standard di codifica e aggiornalo spesso. Prova a imparare dai tuoi bug. Scopri perché è stato creato un bug e cerca di evitarlo utilizzando gli standard di codifica.

I nostri standard di codifica hanno attualmente circa 20 pagine, un mix di Java Coding Standards, Google Obj-C / C ++ Standards e le nostre aggiunte. Documenta il tuo codice, usa rientri standard, spazi bianchi e righe vuote nei posti giusti ecc.

Sii più funzionale .

Objective-C è un linguaggio orientato agli oggetti, ma il framework Cocoa è consapevole dello stile funzionale ed è progettato in molti casi come stile funzionale.

  1. C'è separazione della mutabilità. Usa le classi immutabili come primario e l'oggetto mutabile come secondario. Ad esempio, utilizzare NSArray principalmente e utilizzare NSMutableArray solo quando è necessario.

  2. Esistono funzioni pure. Non così tanti, acquistare molte delle API del framework sono progettate come pura funzione. Guarda funzioni come CGRectMake () o CGAffineTransformMake () . Ovviamente la forma del puntatore sembra più efficiente. Tuttavia, l'argomento indiretto con i puntatori non può offrire effetti collaterali gratuiti. Progetta strutture il più puramente possibile. Separare gli oggetti stato pari. Usa -copy invece di -retain quando passi un valore ad un altro oggetto. Perché lo stato condiviso può influenzare silenziosamente la mutazione al valore in un altro oggetto. Quindi non può essere privo di effetti collaterali. Se si dispone di un valore da esterno a oggetto, copiarlo. Quindi è anche importante progettare lo stato condiviso il più minimamente possibile.

Tuttavia, non aver paura di usare anche funzioni impure.

  1. C'è una valutazione pigra. Guarda qualcosa come - [UIViewController view] proprietà. La vista non verrà creata quando viene creato l'oggetto. Verrà creato quando il chiamante legge la proprietà view per la prima volta. UIImage non verrà caricato fino a quando non verrà effettivamente disegnato. Esistono molte implementazioni come questa progettazione. Questo tipo di progetti sono molto utili per la gestione delle risorse, ma se non si conosce il concetto di valutazione pigra, non è facile comprenderne il comportamento.

  2. C'è chiusura. Usa i blocchi C il più possibile. Questo semplificherà notevolmente la tua vita. Ma leggi ancora una volta sulla gestione della memoria a blocchi prima di usarlo.

  3. C'è un GC semi-automatico. NSAutoreleasePool. Usa -autorelease primario. Usa il manuale -retain / -release secondario quando ne hai veramente bisogno. (es: ottimizzazione della memoria, eliminazione esplicita delle risorse)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top