Quelles sont les meilleures pratiques que vous utilisez pour écrire Objective-C et Cocoa?

Je connais le HIG (ce qui est très pratique!), Mais quelles pratiques de programmation utilisez-vous lors de l'écriture d'Objective-C, et plus particulièrement lors de l'utilisation de Cocoa (ou CocoaTouch).

Il y a quelques choses que j'ai commencé à faire que je ne pense pas être standard:

1) Avec l'avènement des propriétés, je n'utilise plus "_" pour préfixer les variables de class "privées". Après tout, si une variable peut être accessible par d'autres classs ne devrait pas avoir une propriété pour cela? J'ai toujours détesté le préfixe "_" pour rendre le code plus laid, et maintenant je peux le laisser de côté.

2) En parlant de choses privées, je préfère placer les définitions de methods privées dans le file .m dans une extension de class comme ceci:

#import "MyClass.h" @interface MyClass () - (void) someMethod; - (void) someOtherMethod; @end @implementation MyClass 

Pourquoi encombrer le file .h avec des choses que les étrangers ne devraient pas se soucier? Le empty () fonctionne pour les catégories privées dans le file .m, et émet des avertissements de compilation si vous n'implémentez pas les methods déclarées.

3) J'ai pris de mettre dealloc en haut du file .m, juste en dessous des directives @synthesize. Ne devrait-il pas être ce que vous êtes en haut de la list des choses que vous voulez penser dans une class? C'est particulièrement vrai dans un environnement comme l'iPhone.

3.5) Dans les cellules de tableau, rendre chaque élément (y compris la cellule elle-même) opaque pour la performance. Cela signifie définir la couleur d'arrière-plan appropriée dans tout.

3.6) Lors de l'utilisation d'un NSURLConnection, vous pouvez très bien vouloir implémenter la méthode delegate:

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

Je trouve que la plupart des appels Web sont très singuliers et c'est plus l'exception que la règle que vous voulez que les réponses soient mises en cache, en particulier pour les appels de service Web. Implémenter la méthode comme indiqué désactive la caching des réponses.

Vous findez également quelques bons conseils spécifiques à l'iPhone de Joseph Mattiello (reçus sur une list de diffusion iPhone). Il y en a d'autres, mais ce sont les plus utiles que je pensais (notez que quelques bits ont été légèrement modifiés depuis l'original pour inclure les détails offerts dans les réponses):

4) N'utilisez que la double précision si vous devez le faire, par exemple lorsque vous travaillez avec CoreLocation. Assurez-vous de mettre fin à vos constantes dans 'f' pour que gcc les stocke comme des flottants.

 float val = someFloat * 2.2f; 

Ceci est surtout important quand someFloat peut être un double, vous n'avez pas besoin des maths en mode mixte, puisque vous perdez la précision de 'val' sur le stockage. Alors que les nombres à floating point sont pris en charge dans le matériel sur les iPhones, il peut encore prendre plus de time pour faire de l'arithmétique à double précision par opposition à la précision simple. Les references:

  • Double vs float sur l'iPhone
  • iPhone / iPad mathématiques double précision

Sur les téléphones plus anciens, on suppose que les calculs fonctionnent à la même vitesse mais vous pouvez avoir plus de composants de précision simple dans les registres que dans les doubles, donc pour de nombreux calculs, la précision simple finira par être plus rapide.

5) Définissez vos propriétés comme nonatomic . Ils sont atomic par défaut et lors de la synthèse, le code sémaphore sera créé pour éviter les problèmes de multi-threading. 99% d'entre vous n'ont probablement pas besoin de s'inquiéter à ce sujet et le code est beaucoup less gonflé et plus efficace en memory lorsqu'il est défini sur nonatomic.

6) SQLite peut être un moyen très, très rapide de mettre en cache de grands sets de données. Une application cartographique peut par exemple mettre en cache ses tuiles dans des files SQLite. La partie la plus coûteuse est l'E / S disque. Evitez de nombreuses petites écritures en envoyant BEGIN; et COMMIT; entre de gros blocs. Nous utilisons par exemple une timer de 2 secondes qui se réinitialise à chaque nouvelle soumission. Quand il expire, nous envoyons COMMIT; , ce qui entraîne toutes vos écritures dans un gros morceau. SQLite stocke datatables de transaction sur le disque et l'encapsulation Begin / End évite la création de nombreux files de transaction, regroupant toutes les transactions en un seul file.

En outre, SQL bloquera votre interface graphique si elle se trouve sur votre thread principal. Si vous avez une très longue requête, c'est une bonne idée de stocker vos requêtes en tant qu'objects statiques, et exécutez votre SQL sur un thread séparé. Assurez-vous d'envelopper tout ce qui modifie la database pour les strings de requête dans les @synchronize() {} . Pour les requêtes courtes, il suffit de laisser les choses sur le fil principal pour plus de commodité.

Plus de conseils d'optimization de SQLite sont ici, bien que le document semble périmé beaucoup de points sont probablement encore bons;

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

N'utilisez pas de strings inconnues comme strings de format

Lorsque les methods ou fonctions prennent un argument de string de format, vous devez vous assurer que vous avez le contrôle sur le contenu de la string de format.

Par exemple, lors de la journalisation des strings, il est tentant de passer la variable string comme unique argument de NSLog :

  NSSsortingng *aSsortingng = // get a ssortingng from somewhere; NSLog(aSsortingng); 

Le problème avec ceci est que la string peut contenir des caractères qui sont interprétés en tant que strings de format. Cela peut entraîner des erreurs de sortie, des plantages et des problèmes de security. Au lieu de cela, vous devez replace la variable string par une string de format:

  NSLog(@"%@", aSsortingng); 

Utilisez les conventions et la terminologie Cocoa standard de nommage et de mise en forme plutôt que celles auxquelles vous êtes habitué dans un autre environnement. Il y a beaucoup de développeurs Cocoa, et quand un autre d'entre eux commence à travailler avec votre code, il sera beaucoup plus accessible s'il ressemble et ressemble à d'autres codes Cocoa.

Exemples de quoi faire et de ne pas faire:

  • Ne déclarez pas l' id m_something; dans l'interface d'un object et l'appeler une variable ou un champ membre ; utiliser something ou _something something pour son nom et l'appeler une variable d'instance .
  • Ne nommez pas getter -getSomething ; le bon nom de Cocoa est juste -something .
  • Ne nommez pas un setter -something: ça devrait être -setSomething:
  • Le nom de la méthode est intercalé avec les arguments et inclut des deux-points; c'est -[NSObject performSelector:withObject:] , pas NSObject::performSelector .
  • Utilisez des inter-majuscules (CamelCase) dans les noms de methods, les parameters, les variables, les noms de classs, etc. plutôt que dans les sous-barres (underscores).
  • Les noms de class commencent par une lettre majuscule, une variable et un nom de méthode avec une minuscule.

Quoi que vous fassiez, n'utilisez pas la notation hongroise Win16 / Win32. Même Microsoft a renoncé à cela avec le passage à la plate-forme .NET.

IBOutlets

Historiquement, la memory management des points de vente a été médiocre. La meilleure pratique actuelle consiste à déclarer les points de vente en tant que propriétés:

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

L'utilisation de propriétés rend la sémantique de memory management claire; il fournit également un model cohérent si vous utilisez la synthèse de variables d'instance.

Utilisez l'parsingur statique LLVM / Clang

NOTE: Sous Xcode 4, ceci est maintenant embedded dans l'EDI.

Vous utilisez l' parsingur statique Clang pour – sans surprise – parsingr votre code C et Objective-C (pas encore C ++) sur Mac OS X 10.5. Il est sortingvial d'installer et d'utiliser:

  1. Téléchargez la dernière version de cette page .
  2. De la command line, cd à votre directory de projet.
  3. Exécutez scan-build -k -V xcodebuild .

(Il y a des contraintes supplémentaires etc., en particulier vous devez parsingr un projet dans sa configuration "Debug" – voir http://clang.llvm.org/StaticAnalysisUsage.html pour plus de détails – le mais c'est plus ou less ce qui se résume à.)

L'parsingur produit alors pour vous un set de pages Web qui indiquent la gestion probable de la memory et d'autres problèmes de base que le compilateur ne peut pas détecter.

C'est subtile mais pratique. Si vous vous passez en tant que délégué à un autre object, réinitialisez le délégué de cet object avant de le dealloc .

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

En faisant cela, vous vous assurez qu'aucune autre méthode de délégué ne sera envoyée. Comme vous êtes sur le sharepoint vous dealloc et de disparaître dans l'éther, vous voulez vous assurer que rien ne peut vous envoyer plus de messages par accident. Rappelez-vous que self.someObject peut être conservé par un autre object (il peut s'agir d'un singleton ou du pool autorelease ou autre) et jusqu'à ce que vous lui disiez "arrêtez de m'envoyer des messages!", Il pense que votre object est sur le point d'être libéré. est un jeu équitable.

Entrer dans cette habitude vous épargnera de nombreux accidents étranges qui sont difficiles à déboguer.

Le même principe s'applique à l'observation de la valeur des keys et aux NSNotifications également.

Modifier:

Encore plus défensif, changez:

 self.someObject.delegate = NULL; 

dans:

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

@kendell

Au lieu de:

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

Utilisation:

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

Nouveau dans Objective-C 2.0.

Les extensions de class sont décrites dans la reference Objective-C 2.0 d'Apple.

"Les extensions de class vous permettent de déclarer l'API supplémentaire requirejse pour une class dans des locations autres que dans le bloc @interface de la class primaire"

Donc, ils font partie de la class réelle – et pas une catégorie (privée) en plus de la class. Différence subtile mais importante.

Évitez autorelease

Étant donné que vous (1) n'avez pas de contrôle direct sur leur durée de vie, les objects auto-libérés peuvent persister pendant une période relativement longue et augmenter inutilement l'empreinte memory de votre application. Même si cela peut avoir peu de conséquences sur le post de travail, sur des plates-forms plus contraignantes, cela peut être un problème important. Par conséquent, sur toutes les plates-forms, et en particulier sur les plates-forms plus contraignantes, il est recommandé d'éviter d'utiliser des methods qui mèneraient à des objects auto-libérés. Nous vous encourageons à utiliser le model alloc / init.

Ainsi, plutôt que:

 aVariable = [AClass convenienceMethod]; 

si possible, vous devriez plutôt utiliser:

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

Lorsque vous écrivez vos propres methods renvoyant un object nouvellement créé, vous pouvez tirer parti de la convention de nommage de Cocoa pour signaler au récepteur qu'il doit être libéré en ajoutant le nom de la méthode "new".

Ainsi, au lieu de:

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

tu pourrais écrire:

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

Comme le nom de la méthode commence par "new", les consommateurs de votre API savent qu'ils sont responsables de la libération de l'object reçu (voir, par exemple, la méthode newObject de NSObjectController ).

(1) Vous pouvez prendre le contrôle en utilisant vos propres pools de autorelease locaux. Pour plus d'informations à ce sujet, consultez Autorelease Pools .

Certains d'entre eux ont déjà été mentionnés, mais voici ce que je peux penser de haut de la tête:

  • Suivez les règles de nommage de KVO. Même si vous n'utilisez pas KVO maintenant, dans mon expérience souvent, c'est toujours bénéfique à l'avenir. Et si vous utilisez KVO ou des bindings, vous devez savoir que les choses fonctionnent comme elles le devraient. Cela couvre non seulement les methods d'accesseur et les variables d'instance, mais aussi les relations à-plusieurs, la validation, les keys dépendantes auto-notifiantes, etc.
  • Mettez les methods privées dans une catégorie. Pas seulement l'interface, mais aussi l'implémentation. Il est bon d'avoir une certaine distance conceptuelle entre les methods privées et non privées. J'inclus tout dans mon file .m.
  • Placez les methods de fil d'arrière-plan dans une catégorie. Comme ci-dessus. J'ai trouvé qu'il est bon de garder une barrière conceptuelle claire quand on pense à ce qui est sur le fil principal et ce qui ne l'est pas.
  • Utilisez la #pragma mark [section] . Habituellement je grouper par mes propres methods, les rlocations de chaque sous-class, et toute information ou protocole formel. Cela rend beaucoup plus facile de sauter exactement à ce que je cherche. Sur le même sujet, regroupez des methods similaires (comme les methods déléguées d'une vue table), ne les collez pas n'importe où.
  • Préfixe les methods privées et ivars avec _. J'aime son apparence, et je suis less susceptible d'utiliser un ivar quand je parle d'une propriété par accident.
  • N'utilisez pas de methods / propriétés mutator dans init & dealloc. Je n'ai jamais rien eu de mal à cause de cela, mais je peux voir la logique si vous changez la méthode pour faire quelque chose qui dépend de l'état de votre object.
  • Mettez IBOutlets dans les propriétés. En fait, je viens de lire celui-ci ici, mais je vais commencer à le faire. Indépendamment de tous les avantages de la memory, il semble mieux stylistiquement (au less pour moi).
  • Évitez d'écrire du code dont vous n'avez absolument pas besoin. Cela couvre vraiment beaucoup de choses, comme faire des ivars quand un #define fera, ou mettre en cache un tableau au lieu de le sortinger chaque fois que datatables sont nécessaires. Il y a beaucoup de choses que je pourrais dire à ce sujet, mais la ligne du bas est de ne pas écrire de code jusqu'à ce que vous en ayez besoin, ou le profileur vous le request. Cela rend les choses beaucoup plus faciles à maintenir à long terme.
  • Terminez ce que vous commencez. Avoir beaucoup de code à moitié fini, buggé est le moyen le plus rapide de tuer un projet mort. Si vous avez besoin d'une méthode stub qui vous convient, indiquez-la simplement en mettant NSLog( @"stub" ) intérieur, ou bien vous voulez garder une trace des choses.

Écrire des tests unitaires. Vous pouvez tester beaucoup de choses dans Cocoa qui pourraient être plus difficiles dans d'autres frameworks. Par exemple, avec le code d'interface user, vous pouvez généralement vérifier que les choses sont connectées comme elles le devraient et avoir confiance qu'elles fonctionneront lorsqu'elles seront utilisées. Et vous pouvez configurer l'état et appeler les methods de délégué facilement pour les tester.

Vous n'avez pas non plus de visibilité par rapport à une méthode privée ou protégée par rapport à une méthode privée, ce qui vous empêche d'écrire des tests pour vos internes.

Règle d'or: Si vous alloc alors vous release !

MISE À JOUR: Sauf si vous utilisez ARC

N'écrivez pas Objective-C comme s'il s'agissait de Java / C # / C ++ / etc.

Une fois, j'ai vu une équipe habituée à l'écriture d'applications Web Java EE essayer d'écrire une application de bureau Cocoa. Comme s'il s'agissait d'une application Web Java EE. Il y avait beaucoup de AbstractFooFactory et FooFactory et IFoo et Foo volaient quand tout ce dont ils avaient vraiment besoin était une class Foo et peut-être un protocole Fooable.

Une partie de s'assurer que vous ne faites pas cela est de vraiment comprendre les différences dans la langue. Par exemple, vous n'avez pas besoin des classs d'usine et d'usine abstraites ci-dessus car les methods de class Objective-C sont dissortingbuées aussi dynamicment que les methods d'instance et peuvent être remplacées dans les sous-classs.

Assurez-vous de mettre en signet la page Debugging Magic . Cela devrait être votre premier arrêt lorsque vous vous frappez la tête contre un mur tout en essayant de find la source d'un insecte Cocoa.

Par exemple, il vous indiquera comment find la méthode dans laquelle vous avez alloué de la memory pour la première fois, ce qui provoquera des plantages plus tard (comme lors de la fin de l'application).

Trier les strings selon les besoins de l'user

Lorsque vous sortingez des strings à présenter à l'user, vous ne devez pas utiliser la méthode simple compare: :. Au lieu de cela, vous devez toujours utiliser des methods de comparaison localisées, telles que localizedCompare: ou localizedCaseInsensitiveCompare:

Pour plus de détails, voir Recherche, comparaison et sorting des strings .

Essayez d'éviter ce que j'ai décidé d'appeler Newbiecategoryaholism. Quand les nouveaux venus découvrent Objective-C, ils vont souvent à l'état sauvage, ajoutant de petites catégories utiles à chaque class ( "Quoi?", Je peux append une méthode pour convertir un nombre en numbers romains en NSNumber rock! ).

Ne fais pas ça.

Votre code sera plus portable et plus facile à comprendre avec des dizaines de petites methods de catégorie saupoudrées sur deux douzaines de cours de base.

La plupart du time, quand vous pensez vraiment avoir besoin d'une méthode de catégorie pour vous aider à rationaliser du code, vous ne finirez jamais par réutiliser la méthode.

Il y a aussi d'autres dangers, à less que vous ne fassiez appel à vos methods de catégorie (et qui, outre le ddribin complètement fou?), A une chance qu'Apple, ou un plugin, ou quelque chose d'autre dans votre espace d'adresse définisse la même catégorie méthode avec le même nom avec un effet secondaire légèrement différent ….

D'ACCORD. Maintenant que vous avez été averti, ignorez le "ne faites pas cette partie". Mais exercez une extrême retenue.

Résister à la sous-classification du monde. Dans Cocoa, beaucoup de choses sont faites par la délégation et l'utilisation du runtime sous-jacent qui, dans d'autres frameworks, se fait par sous-class.

Par exemple, dans Java, vous utilisez beaucoup les sous-classs de *Listener anonymes *Listener et dans .NET, vous utilisez EventArgs vos sous-classs EventArgs . Dans Cocoa, vous ne faites pas non plus – l'action-cible est utilisée à la place.

properties déclarées

Vous devez généralement utiliser la fonctionnalité Objective-C 2.0 Declared Properties pour toutes vos propriétés. S'ils ne sont pas publics, ajoutez-les dans une extension de class. L'utilisation des propriétés déclarées rend la sémantique de memory management immédiatement plus claire et facilite la vérification de votre méthode dealloc. Si vous regroupez vos déclarations de propriétés, vous pouvez les parsingr rapidement et les comparer à l'implémentation de votre méthode dealloc.

Vous devriez réfléchir avant de ne pas marquer les propriétés comme «nonatomic». Comme le note le Guide du langage de programmation Objective C , les propriétés sont atomiques par défaut et entraînent une surcharge considérable. De plus, simplement rendre toutes vos propriétés atomiques ne rend pas votre application thread-safe. Notez également, bien sûr, que si vous ne spécifiez pas 'nonatomic' et implémentez vos propres methods d'accesseur (plutôt que de les synthétiser), vous devez les implémenter de manière atomique.

Pensez aux valeurs nulles

Comme le note cette question , les messages à nil sont valables en Objective-C. Bien que ce soit souvent un avantage – conduisant à un code plus propre et plus naturel – la fonctionnalité peut parfois conduire à des bugs particuliers et difficiles à traquer si vous obtenez une valeur nil lorsque vous ne l'attendiez pas.

Utilisez NSAssert et vos amis. J'utilise nil comme object valide tout le time … surtout envoyer des messages à zéro est parfaitement valide dans Obj-C. Cependant, si je veux vraiment m'assurer de l'état d'une variable, j'utilise NSAssert et NSParameterAssert, ce qui aide à localiser facilement les problèmes.

Simple but oft-forgotten one. According to spec:

In general, methods in different classs that have the same selector (the same name) must also share the same return and argument types. This constraint is imposed by the comstackr to allow dynamic binding.

in which case all the same named selectors, even if in different classs , will be regarded as to have identical return/argument types. Here is a simple example.

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

If you're using Leopard (Mac OS X 10.5) or later, you can use the Instruments application to find and track memory leaks. After building your program in Xcode, select Run > Start with Performance Tool > Leaks.

Even if your app doesn't show any leaks, you may be keeping objects around too long. In Instruments, you can use the ObjectAlloc instrument for this. Select the ObjectAlloc instrument in your Instruments document, and bring up the instrument's detail (if it isn't already showing) by choosing View > Detail (it should have a check mark next to it). Under "Allocation Lifespan" in the ObjectAlloc detail, make sure you choose the radio button next to "Created & Still Living".

Now whenever you stop recording your application, selecting the ObjectAlloc tool will show you how many references there are to each still-living object in your application in the "# Net" column. Make sure you not only look at your own classs, but also the classs of your NIB files' top-level objects. For example, if you have no windows on the screen, and you see references to a still-living NSWindow, you may have not released it in your code.

Clean up in dealloc.

This is one of the easiest things to forget – esp. when coding at 150mph. Always, always, always clean up your atsortingbutes/member variables in dealloc.

I like to use Objc 2 atsortingbutes – with the new dot notation – so this makes the cleanup painless. Often as simple as:

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

This will take care of the release for you and set the atsortingbute to NULL (which I consider defensive programming – in case another method further down in dealloc accesses the member variable again – rare but could happen).

With GC turned on in 10.5, this isn't needed so much any more – but you might still need to clean up others resources you create, you can do that in the finalize method instead.

All these comments are great, but I'm really surprised nobody mentioned Google's Objective-C Style Guide that was published a while back. I think they have done a very thorough job.

Also, semi-related topic (with room for more responses!):

What are those little Xcode tips & sortingcks you wish you knew about 2 years ago? .

Don't forget that NSWindowController and NSViewController will release the top-level objects of the NIB files they govern.

If you manually load a NIB file, you are responsible for releasing that NIB's top-level objects when you are done with them.

One rather obvious one for a beginner to use: utilize Xcode's auto-indentation feature for your code. Even if you are copy/pasting from another source, once you have pasted the code, you can select the entire block of code, right click on it, and then choose the option to re-indent everything within that block.

Xcode will actually parse through that section and indent it based on brackets, loops, etc. It's a lot more efficient than hitting the space bar or tab key for each and every line.

I know I overlooked this when first getting into Cocoa programming.

Make sure you understand memory management responsibilities regarding NIB files. You are responsible for releasing the top-level objects in any NIB file you load. Read Apple's Documentation on the subject.

Turn on all GCC warnings, then turn off those that are regularly caused by Apple's headers to reduce noise.

Also run Clang static analysis frequently; you can enable it for all builds via the "Run Static Analyzer" build setting.

Write unit tests and run them with each build.

Variables and properties

1/ Keeping your headers clean, hiding implementation
Don't include instance variables in your header. Private variables put into class continuation as properties. Public variables declare as public properties in your header. If it should be only read, declare it as readonly and overwrite it as readwrite in class continutation. Basically I am not using variables at all, only properties.

2/ Give your properties a non-default variable name, example:

 @synthesize property = property_; 

Reason 1: You will catch errors caused by forgetting "self." when assigning the property. Reason 2: From my experiments, Leak Analyzer in Instruments has problems to detect leaking property with default name.

3/ Never use retain or release directly on properties (or only in very exceptional situations). In your dealloc just assign them a nil. Retain properties are meant to handle retain/release by themselves. You never know if a setter is not, for example, adding or removing observers. You should use the variable directly only inside its setter and getter.

Vues

1/ Put every view definition into a xib, if you can (the exception is usually dynamic content and layer settings). It saves time (it's easier than writing code), it's easy to change and it keeps your code clean.

2/ Don't try to optimize views by decreasing the number of views. Don't create UIImageView in your code instead of xib just because you want to add subviews into it. Use UIImageView as background instead. The view framework can handle hundreds of views without problems.

3/ IBOutlets don't have to be always retained (or strong). Note that most of your IBOutlets are part of your view hierarchy and thus implicitly retained.

4/ Release all IBOutlets in viewDidUnload

5/ Call viewDidUnload from your dealloc method. It is not implicitly called.

Mémoire

1/ Autorelease objects when you create them. Many bugs are caused by moving your release call into one if-else branch or after a return statement. Release instead of autorelease should be used only in exceptional situations – eg when you are waiting for a runloop and you don't want your object to be autoreleased too early.

2/ Even if you are using Authomatic Reference Counting, you have to understand perfectly how retain-release methods work. Using retain-release manually is not more complicated than ARC, in both cases you have to thing about leaks and retain-cycles. Consider using retain-release manually on big projects or complicated object hierarchies.

commentaires

1/ Make your code autodocumented. Every variable name and method name should tell what it is doing. If code is written correctly (you need a lot of practice in this), you won't need any code comments (not the same as documentation comments). Algorithms can be complicated but the code should be always simple.

2/ Sometimes, you'll need a comment. Usually to describe a non apparent code behavior or hack. If you feel you have to write a comment, first try to rewrite the code to be simpler and without the need of comments.

Indentation

1/ Don't increase indentation too much. Most of your method code should be indented on the method level. Nested blocks (if, for etc.) decrease readability. If you have three nested blocks, you should try to put the inner blocks into a separate method. Four or more nested blocks should be never used. If most of your method code is inside of an if, negate the if condition, example:

 if (self) { //... long initialization code ... } return self; 
 if (!self) { return nil; } //... long initialization code ... return self; 

Understand C code, mainly C structs

Note that Obj-C is only a light OOP layer over C language. You should understand how basic code structures in C work (enums, structs, arrays, pointers etc). Exemple:

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

is the same as:

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

And many more

Mantain your own coding standards document and update it often. Try to learn from your bugs. Understand why a bug was created and try to avoid it using coding standards.

Our coding standards have currently about 20 pages, a mix of Java Coding Standards, Google Obj-C/C++ Standards and our own addings. Document your code, use standard standard indentation, white spaces and blank lines on the right places etc.

Be more functional .

Objective-C is object-oriented language, but Cocoa framework functional-style aware, and is designed functional style in many cases.

  1. There is separation of mutability. Use immutable classs as primary, and mutable object as secondary. For instance, use NSArray primarily, and use NSMutableArray only when you need.

  2. There is pure functions. Not so many, buy many of framework APIs are designed like pure function. Look at functions such as CGRectMake() or CGAffineTransformMake() . Obviously pointer form looks more efficient. However indirect argument with pointers can't offer side-effect-free. Design structures purely as much as possible. Separate even state objects. Use -copy instead of -retain when passing a value to other object. Because shared state can influence mutation to value in other object silently. So can't be side-effect-free. If you have a value from external from object, copy it. So it's also important designing shared state as minimal as possible.

However don't be afraid of using impure functions too.

  1. There is lazy evaluation. See something like -[UIViewController view] property. The view won't be created when the object is created. It'll be created when caller reading view property at first time. UIImage will not be loaded until it actually being drawn. There are many implementation like this design. This kind of designs are very helpful for resource management, but if you don't know the concept of lazy evaluation, it's not easy to understand behavior of them.

  2. There is closure. Use C-blocks as much as possible. This will simplify your life greatly. But read once more about block-memory-management before using it.

  3. There is semi-auto GC. NSAutoreleasePool. Use -autorelease primary. Use manual -retain/-release secondary when you really need. (ex: memory optimization, explicit resource deletion)