Risposte:
Ho iniziato a fare alcune cose che non credo siano standard:
1) Con l'avvento delle proprietà, non uso più "_" per aggiungere il prefisso alle variabili di classe "private". 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) Parlando 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 non dovrebbero interessare agli estranei? Empty () funziona per le categorie private nel file .m e genera avvisi di compilazione se non si implementano i metodi dichiarati.
3) Ho preso a mettere dealloc nella parte superiore del file .m, proprio 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 che la regola in cui vorrai che le risposte vengano memorizzate nella cache, soprattutto 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 sono stati 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 costanti in 'f' per fare in modo che gcc le memorizzi come float.
float val = someFloat * 2.2f;
Questo è per lo più importante quando someFloat
potrebbe effettivamente essere un doppio, non è necessaria la 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 nei registri si possono avere più componenti a precisione singola che doppi, quindi per molti calcoli la precisione singola finirà per essere più veloce.
5) Imposta le tue proprietà come nonatomic
. Sono atomic
di default e al momento della 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 archivia i dati delle transazioni su disco e, facendo questo, il wrapping Begin / End evita la creazione di molti file delle transazioni, 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 avvolgere tutto ciò che modifica il database per le stringhe di query in @synchronize() {}
blocchi. Per domande brevi, lascia semplicemente le cose sul thread principale per una maggiore comodità.
Altri suggerimenti per l'ottimizzazione di SQLite sono qui, sebbene il documento appaia obsoleto molti dei punti sono probabilmente ancora validi;
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Quando metodi o 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 di denominazione e formattazione del cacao piuttosto che qualsiasi cosa a cui sei abituato da un altro ambiente. Ci sono molti sviluppatori di Cocoa là fuori e quando un altro 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:
id m_something;
nell'interfaccia di un oggetto e chiamarlo una variabile o un campo membro ; usa something
o _something
per il suo nome e chiamalo una variabile di istanza .-getSomething
; il nome proprio di cacao è giusto -something
.-something:
; dovrebbe essere-setSomething:
-[NSObject performSelector:withObject:]
è NSObject::performSelector
.Qualunque cosa tu faccia, non usare la notazione ungherese in stile Win16 / Win32. Perfino Microsoft ha rinunciato a questo con il passaggio alla piattaforma .NET.
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 si utilizza la sintesi delle variabili di istanza.
NOTA: Sotto Xcode 4 questo è ora incorporato nell'IDE.
Si utilizza il Clang Static Analyzer a - non sorprende - analizzare il C e il codice Objective-C (non C ++ ancora) su Mac OS X 10.5. È banale da installare e utilizzare:
cd
alla directory del progetto.scan-build -k -V xcodebuild
.(Ci sono alcuni vincoli aggiuntivi ecc., In particolare è necessario analizzare un progetto nella sua configurazione "Debug" - vedere http://clang.llvm.org/StaticAnalysisUsage.html per i dettagli - ma è più o meno a cosa si riduce.)
L'analizzatore quindi produce 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, ripristina il delegato dell'oggetto prima di te 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
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 gli dici "smetti di inviarmi messaggi!", Pensa che il tuo oggetto sia quasi in procinto di essere distribuito è un gioco equo.
Entrare in questa abitudine ti salverà da molti strani incidenti che sono un dolore per il debug.
Lo stesso principio si applica all'osservazione dei valori chiave e anche alle notifiche NS.
Modificare:
Ancora più difensivo, cambia:
self.someObject.delegate = NULL;
in:
if (self.someObject.delegate == self)
self.someObject.delegate = NULL;
Memory Management Programming Guide for Cocoa
: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
nil == NULL
. Sono esattamente gli stessi tranne che nil
è un id
ed NULL
è un void *
. La tua affermazione non è vera.
@kendell
Invece di:
@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end
Uso:
@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 API richieste aggiuntive per una classe in posizioni diverse dal blocco @interface della classe primaria"
Quindi fanno parte della classe reale e NON una categoria (privata) in aggiunta alla classe. Differenza sottile ma importante.
()
invece di (Private)
(o qualche altro nome di categoria): puoi dichiarare le proprietà come readwrite mentre al pubblico sono solo di sola lettura. :)
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 prassi per evitare l'uso di metodi che porterebbero a oggetti rilasciati automaticamente e si consiglia invece di utilizzare il modello alloc / init.
Pertanto, anziché:
aVariable = [AClass convenienceMethod];
dove possibile, dovresti invece usare:
aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];
Quando si scrivono i propri metodi che restituiscono un oggetto appena creato, è possibile sfruttare la convenzione di denominazione di Cocoa per segnalare al destinatario che deve essere rilasciato anteponendo il nome del metodo con "nuovo".
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, il newObject
metodo NSObjectController ).
(1) Puoi prendere il controllo usando i tuoi pool di autorelease locali. Per ulteriori informazioni, consultare Pool di autorelease .
NSAutoreleasePool
. Ma solo dopo aver confermato che questo è davvero un problema. Ottimizzazione prematura e tutto il resto ...
Alcuni di questi sono già stati menzionati, ma ecco cosa posso pensare dalla cima della mia testa:
#pragma mark [section]
. 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.#define
o memorizzare nella cache un array invece di ordinarlo ogni volta che sono necessari i dati. C'è molto che potrei dire a 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.NSLog( @"stub" )
dentro, o comunque vuoi tenere traccia delle cose.Finish what you start
te puoi anche usare // TODO:
per contrassegnare il codice per il completamento che apparirà nel menu a discesa.
Scrivi unit test. Puoi testare molte 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 facilmente e invocare 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 tu alloc
allora release
!
AGGIORNAMENTO: A meno che non si stia utilizzando ARC
copy
, mutableCopy
, new
o retain
.
Non scrivere Objective-C come se fosse Java / C # / C ++ / etc.
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 possibilmente un protocollo Fooable.
Parte della garanzia di non farlo è comprendere veramente le differenze nella lingua. Ad esempio, non sono necessarie le classi factory e factory astratte sopra perché i metodi della classe Objective-C vengono inviati in modo dinamico come i metodi di istanza e possono essere sovrascritti in sottoclassi.
Assicurati di aggiungere la pagina di Debug Magic ai segnalibri . Questa dovrebbe essere la tua prima fermata quando sbatti la testa contro un muro mentre cerchi di trovare la fonte di un bug di cacao.
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).
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 ( "Cosa? Posso aggiungere un metodo per convertire un numero in numeri romani in NSNumber su!" ).
Non farlo
Il tuo codice sarà più portatile e più facile da capire senza decine 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 il 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 ddribin assolutamente folle?) C'è la possibilità che Apple, o un plug-in o qualcos'altro in esecuzione nel tuo spazio degli indirizzi definisca anche la stessa categoria metodo con lo stesso nome con un effetto collaterale leggermente diverso ....
OK. Ora che sei stato avvisato, ignora il "non fare questa parte". Ma esercitare estrema moderazione.
Resisti alla sottoclasse del mondo. In Cocoa molto si fa attraverso la delega e l'uso del runtime sottostante che in altri framework avviene attraverso la sottoclasse.
Ad esempio, in Java usi molto le istanze di *Listener
sottoclassi anonime e in .NET usi molto le tue EventArgs
sottoclassi. In Cocoa, non lo fai neanche tu: al suo posto viene utilizzata l'azione bersaglio.
Quando si ordinano le stringhe da presentare all'utente, non è necessario utilizzare il compare:
metodo semplice . Invece, dovresti sempre usare metodi di confronto localizzati comelocalizedCompare:
o localizedCaseInsensitiveCompare:
.
Per ulteriori dettagli, consultare Ricerca, confronto e ordinamento di stringhe .
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 osserva la Guida al linguaggio di programmazione dell'obiettivo C , le proprietà sono atomiche per impostazione predefinita e comportano 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.
Come nota questa domanda , i messaggi 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 nil
valore quando non te lo aspettavi.
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, i metodi in diverse classi che hanno lo stesso selettore (lo stesso nome) devono anche condividere gli stessi tipi di ritorno e argomento. Questo vincolo è imposto dal compilatore per consentire l'associazione dinamica.
nel qual caso tutti gli stessi selettori nominati, anche se in classi diverse , saranno considerati come identici tipi di ritorno / argomento. Qui c'è 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 stai utilizzando Leopard (Mac OS X 10.5) o versioni successive, puoi utilizzare l'applicazione Instruments per trovare e tenere traccia delle perdite di memoria. Dopo aver creato il programma in Xcode, selezionare 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 tuo documento Instruments e visualizza i dettagli dello strumento (se non è già mostrato) scegliendo Visualizza> Dettaglio (dovrebbe avere un segno di spunta accanto ad esso). Sotto "Durata della allocazione" nel dettaglio ObjectAlloc, assicurati di scegliere il pulsante di opzione accanto a "Creato e ancora vivente".
Ora, ogni volta che interrompi la registrazione della tua applicazione, selezionando lo strumento ObjectAlloc ti mostrerà quanti riferimenti ci sono per ogni oggetto ancora vivo nella tua applicazione nella colonna "# Net". 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 in 10.5, questo non è più necessario, ma potresti comunque aver bisogno di ripulire le altre risorse che crei, invece puoi farlo nel metodo finalize.
-init
e -dealloc
metodi è disponibile qui: mikeash.com/?page=pyblog/…
Tutti questi commenti sono fantastici, ma sono davvero sorpreso che nessuno abbia menzionato la Guida allo stile Objective-C di Google che è stata pubblicata qualche tempo fa. Penso che abbiano svolto un lavoro molto approfondito.
Inoltre, argomento semi-correlato (con spazio per più risposte!):
Quali sono quei trucchi e suggerimenti su Xcode che vorresti conoscere 2 anni fa? .
Uno piuttosto ovvio per un principiante: utilizzare la funzione di rientro automatico di Xcode per il proprio 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.
Assicurarsi 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 la 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 l'impostazione di build "Esegui analizzatore statico".
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 "sé". 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 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 gerarchia di visualizzazione e quindi implicitamente mantenuti.
4 / Rilasciare tutti gli IBOutlet in viewDidUnload
5 / Call viewDidScarica dal tuo metodo dealloc. Non è implicitamente chiamato.
Memoria
1 / Rilascio automatico degli oggetti quando vengono creati. Molti bug sono causati dallo spostamento della chiamata di rilascio in un ramo if-else o dopo una dichiarazione di ritorno. Rilascio invece del rilascio automatico dovrebbe essere utilizzato solo in situazioni eccezionali, ad esempio quando si è in attesa di un runloop e non si desidera che il proprio oggetto venga rilasciato automaticamente in anticipo.
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 l'utilizzo manuale della conservazione in progetti di grandi dimensioni 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.
dentellatura
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, ad 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.
Si noti che Obj-C è solo uno strato 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);
equivale 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 punti giusti, ecc.
Sii più funzionale .
Objective-C è un linguaggio orientato agli oggetti, ma è consapevole dello stile funzionale del framework Cocoa ed è progettato in molti casi uno stile funzionale.
C'è separazione della mutabilità. Usa immutabile classi come primario e l'oggetto mutabile come secondario. Ad esempio, utilizzare NSArray principalmente e utilizzare NSMutableArray solo quando è necessario.
Ci sono 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. Utilizzare -copy
invece di -retain
quando si passa 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.
C'è una valutazione pigra. Vedi qualcosa come la -[UIViewController view]
proprietà. La vista non verrà creata quando viene creato l'oggetto. Verrà creato view
alla prima lettura della proprietà del chiamante . 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.
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.
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)
autorelease
che manterrà la memoria più a lungo in generale, e il manuale retain/release
può ridurre il consumo di memoria nel caso. Tuttavia, dovrebbe essere una guida per l'ottimizzazione di casi speciali (anche se ti senti sempre!), Non può essere la ragione per generalizzare l'ottimizzazione prematura come pratica . E in effetti, il tuo suggerimento non è contrario a me. L'ho menzionato come un caso di