Je connais le HIG (ce qui est très pratique!), Mais quelles pratiques de programmation utilisez-vous pour écrire Objective-C, et plus particulièrement pour utiliser Cocoa (ou CocoaTouch).
J'ai commencé à faire certaines choses que je ne considère pas comme standard:
1) Avec l'avènement des propriétés, je n'utilise plus "_" pour préfixer les variables de classe "privées". Après tout, si une variable peut être accédée par d’autres classes, ne devrait-il pas y avoir une propriété? 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 méthodes privées dans le fichier .m dans une extension de classe comme ceci:
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass
Pourquoi encombrer le fichier .h avec des choses que les étrangers ne devraient pas se soucier? Empty () fonctionne pour les catégories privées dans le fichier .m et émet des avertissements de compilation si vous n'implémentez pas les méthodes déclarées.
3) J'ai commencé à mettre dealloc en haut du fichier .m, juste en dessous des directives @synthesize. Ce que vous désaffectez ne devrait-il pas figurer en haut de la liste des choses auxquelles vous voulez penser en classe? Cela est particulièrement vrai dans un environnement comme l'iPhone.
3.5) Dans les cellules de tableau, rendez chaque élément (y compris la cellule elle-même) opaque pour la performance. Cela signifie que vous définissez la couleur de fond appropriée dans tout.
3.6) Lors de l’utilisation de NSURLConnection, vous voudrez peut-être en règle générale 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 qu’il s’agit plus d’une exception que de la règle voulant que les réponses soient mises en cache, en particulier pour les appels de service Web. L'implémentation de la méthode comme indiqué désactive la mise en cache des réponses.
Joseph Mattiello (reçu sur une liste de diffusion pour iPhone) contient également de bons conseils spécifiques à l’iPhone. Il y en a plus, mais c'étaient les plus utiles, à mon avis (notez que quelques éléments ont été légèrement modifiés par rapport à l'original pour inclure les détails proposés dans les réponses):
4) Utilisez uniquement la double précision si vous devez, par exemple lorsque vous travaillez avec CoreLocation. Assurez-vous de terminer vos constantes en 'f' pour que gcc les stocke en tant que flottants.
float val = someFloat * 2.2f;
Ceci est surtout important lorsque someFloat
peut en réalité être un double, vous n'avez pas besoin du calcul en mode mixte, car vous perdez de la précision dans 'val' lors du stockage. Bien que les nombres à virgule flottante soient pris en charge par le matériel sur les iPhones, l’arithmétique en double précision risque de prendre plus de temps que la simple précision. Références:
Sur les téléphones plus anciens, les calculs fonctionnent supposément à la même vitesse, mais vous pouvez avoir plus de composants à simple précision dans les registres que de doubles, ainsi, 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, un code de sémaphore sera créé pour éviter les problèmes de multi-threading. 99% d’entre vous n’a probablement pas besoin de s’inquiéter à ce sujet et le code est beaucoup moins volumineux et utilise moins la mémoire lorsqu'il est configuré en mode non atomique.
6) SQLite peut être un moyen très rapide de mettre en cache de grands ensembles de données. Une application cartographique, par exemple, peut mettre ses tuiles en cache dans des fichiers SQLite. La partie la plus chère est le disque I/O. Évitez de nombreuses petites écritures en envoyant BEGIN;
et COMMIT;
entre des gros blocs. Nous utilisons par exemple une minuterie de 2 secondes qui se réinitialise à chaque nouvelle soumission. Quand il expire, nous envoyons COMMIT; , ce qui fait que toutes vos écritures vont dans un gros morceau. SQLite stocke les données de transaction sur le disque, ce qui évite la création de nombreux fichiers de transaction en regroupant toutes les transactions dans un seul fichier.
De plus, SQL bloquera votre interface graphique si elle se trouve sur votre thread principal. Si vous avez une très longue requête, il est conseillé de stocker vos requêtes sous forme d'objets statiques et d'exécuter votre code SQL sur un thread distinct. Veillez à envelopper tout ce qui modifie la base de données pour les chaînes de requête dans des blocs @synchronize() {}
. Pour les requêtes courtes, laissez les choses sur le fil principal pour plus de commodité.
Vous trouverez plus de conseils d’optimisation SQLite ici, même si le document semble obsolète et que de nombreux points restent probablement bons;
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Lorsque des méthodes ou des fonctions utilisent un argument de chaîne de format, vous devez vous assurer de contrôler le contenu de la chaîne de format.
Par exemple, lors de la journalisation de chaînes, il est tentant de passer la variable de chaîne comme unique argument à NSLog
:
NSString *aString = // get a string from somewhere;
NSLog(aString);
Le problème, c'est que la chaîne peut contenir des caractères interprétés comme des chaînes de format. Cela peut entraîner des erreurs de sortie, des blocages et des problèmes de sécurité. Au lieu de cela, vous devriez substituer la variable string dans une chaîne de format:
NSLog(@"%@", aString);
Utilisez les conventions et la terminologie de dénomination et de formatage standard de Cocoa plutôt que ce que vous avez l'habitude d'utiliser dans un autre environnement. Il y a beaucoup de développeurs Cocoa, et lorsqu'un autre d'entre eux commence à travailler avec votre code, il sera beaucoup plus accessible s'il ressemble à un autre code Cocoa. .
Exemples de choses à faire et à ne pas faire:
id m_something;
dans l'interface d'un objet et appelez-le un champ variable ou ; utilisez something
ou _something
pour son nom et appelez-le une variable d'instance .-getSomething
; le bon nom de cacao est juste -something
.-something:
; ce devrait être -setSomething:
-[NSObject performSelector:withObject:]
, pas NSObject::performSelector
.Quoi que vous fassiez, ne pas utiliser la notation hongroise Win16/Win32. Même Microsoft a renoncé à cela avec le passage à la plate-forme .NET.
Historiquement, la gestion de la mémoire 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 clarifie la sémantique de la gestion de la mémoire. il fournit également un motif cohérent si vous utilisez la synthèse de variable d'instance.
NOTE: Sous Xcode 4, ceci est maintenant intégré à l'EDI.
Vous utilisez Clang Static Analyzer pour - sans surprise - analyser votre code C et votre code Objective-C (pas encore de C++) sous Mac OS X 10.5. C'est trivial d'installer et d'utiliser:
cd
dans le répertoire de votre projet.scan-build -k -V xcodebuild
.(Il y a quelques contraintes supplémentaires, etc., en particulier vous devriez analyser un projet dans sa configuration "Debug" - voir http://clang.llvm.org/StaticAnalysisUsage.html pour plus de détails - le mais c'est plus ou moins ce que cela revient à).
L'analyseur génère ensuite un ensemble de pages Web indiquant la gestion probable de la mémoire et d'autres problèmes fondamentaux que le compilateur est incapable de détecter.
C'est un subtil mais un pratique. Si vous vous passez en tant que délégué à un autre objet, réinitialisez le délégué de cet objet avant de 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égation ne sera envoyée. Alors que vous êtes sur le point de dealloc
et que vous disparaissez dans l’éther, vous voulez vous assurer que rien ne peut vous envoyer plus de messages par accident. Rappelez-vous que self.someObject pourrait être retenu par un autre objet (un singleton, un groupe d'auto-libérations ou autre) et jusqu'à ce que vous lui disiez "arrêtez de m'envoyer des messages!", Il pense que votre objet est sur le point d'être désalloué. est un jeu juste.
En prenant cette habitude, vous éviterez de nombreux accidents étranges, difficiles à corriger.
Le même principe s'applique à Key Value Observation et à NSNotifications.
Modifier:
Encore plus défensif, le changement:
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 classe sont décrites dans la référence Objective-C 2.0 de Apple.
"Les extensions de classe vous permettent de déclarer une API supplémentaire requise pour une classe dans des emplacements autres que dans le bloc de classe primaire @interface"
Ils font donc partie de la classe actuelle - et PAS une catégorie (privée) en plus de la classe. Différence subtile mais importante.
Comme vous (1) n’avez généralement pas de contrôle direct sur leur durée de vie, les objets auto-libérés peuvent persister relativement longtemps et augmenter inutilement l’empreinte mémoire de votre application. Cela peut avoir peu d’importance sur le bureau, mais sur des plates-formes plus restreintes, cela peut poser un problème important. Par conséquent, sur toutes les plates-formes, et en particulier sur les plates-formes plus contraintes, il est recommandé d'éviter d'utiliser des méthodes qui conduiraient à des objets auto-libérés. Vous êtes plutôt encouragé à utiliser le modèle 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 méthodes qui renvoient un objet nouvellement créé, vous pouvez tirer parti de convention de dénomination de Cocoa pour signaler au destinataire qu'il doit être libéré en ajoutant le nom de la méthode au début de la liste. .
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 "nouveau", les utilisateurs de votre API savent qu'ils sont responsables de la libération de l'objet reçu (voir, par exemple, méthode newObject
de NSObjectController ).
(1) Vous pouvez prendre le contrôle en utilisant vos propres pools d’autorelease locaux. Pour plus d'informations à ce sujet, voir Groupes de libération automatique .
Certains d'entre eux ont déjà été mentionnés, mais voici ce que je peux penser à mon esprit:
#pragma mark [section]
. Généralement, je groupe selon mes propres méthodes, les substitutions de chaque sous-classe et toute information ou protocole formel. Cela facilite beaucoup l'accès à ce que je recherche. Sur le même sujet, regroupez des méthodes similaires (comme les méthodes de délégation d'une vue table), ne les collez pas n'importe où.#define
le fera, ou mettre en cache un tableau au lieu de le trier à chaque fois que les données est nécessaire. Je pourrais en dire beaucoup à ce sujet, mais en bout de ligne, n'écrivez pas de code tant que vous n'en avez pas besoin, ou que le profileur vous le dit. Cela facilite beaucoup les choses à maintenir sur le long terme.NSLog( @"stub" )
à l'intérieur, ou faites comme vous le souhaitez.Ecrire des tests unitaires. Vous pouvez tester beaucoup de choses dans Cocoa qui pourraient être plus difficiles dans d’autres cadres. Par exemple, avec le code d'interface utilisateur, vous pouvez généralement vérifier que les éléments sont connectés comme ils le devraient et qu'ils ont confiance qu'ils fonctionneront lorsqu'ils seront utilisés. Et vous pouvez facilement configurer les méthodes de délégation state & invoke pour les tester.
De plus, vous n'avez pas de visibilité méthode par opposition à méthode protégée par opposition à 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
!
UPDATE: Sauf si vous utilisez ARC
N'écrivez pas Objective-C comme s'il s'agissait de Java/C #/C++/etc.
J'ai déjà vu une équipe habituée à écrire Java des applications Web EE essayant d'écrire une application de bureau Cocoa. Comme s'il s'agissait d'une application Web Java EE. AbstractFooFactory et FooFactory et IFoo et Foo volaient beaucoup alors que tout ce dont ils avaient besoin était une classe Foo et éventuellement un protocole Fooable.
Pour que vous ne le fassiez pas, il est essentiel de bien comprendre les différences linguistiques. Par exemple, vous n'avez pas besoin de la fabrique abstraite et des classes de fabrique ci-dessus, car les méthodes de classe Objective-C sont distribuées de manière aussi dynamique que les méthodes d'instance et peuvent être remplacées dans des sous-classes.
Assurez-vous de marquer la page Magic de débogage . Cela devrait être votre premier arrêt lorsque vous frappez la tête contre un mur tout en essayant de trouver la source d'un virus Cocoa.
Par exemple, il vous indiquera comment trouver la méthode par laquelle vous avez alloué la mémoire pour la première fois, ce qui a causé des plantages (comme lors de la fermeture de l'application).
Lorsque vous triez les chaînes à présenter à l'utilisateur, vous ne devez pas utiliser la méthode simple compare:
. Au lieu de cela, vous devez toujours utiliser des méthodes de comparaison localisées telles que localizedCompare:
ou localizedCaseInsensitiveCompare:
.
Pour plus de détails, voir Recherche, comparaison et tri de chaînes .
Essayez d'éviter ce que j'ai maintenant décidé d'appeler Newbiecategoryaholism. Lorsque les nouveaux venus dans Objective-C découvrent des catégories, ils deviennent souvent fous, ajoutant de petites catégories utiles à chaque classe existante ("Quoi? Je peux ajouter une méthode pour convertir un nombre en chiffres romains en NSNumber!").
Ne fais pas ça.
Votre code sera plus portable et plus facile à comprendre avec des dizaines de méthodes de petites catégories saupoudrées sur deux douzaines de classes de base.
La plupart du temps, lorsque vous pensez réellement avoir besoin d'une méthode de catégorie pour rationaliser certains codes, vous vous rendez compte que vous n'utilisez jamais la méthode.
Il y a aussi d'autres dangers, à moins que vous fassiez des noms avec vos méthodes de catégorie (et qui, en plus de la ddribin complètement insensée, est?), Il y a une chance que Apple, ou un plugin, ou que quelque chose d'autre dans votre espace d'adressage définisse également 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 faites preuve d'une extrême retenue.
Résister à sous-classer le monde. Dans Cocoa, la délégation et l’utilisation du moteur d’exécution sous-jacent sont très répandus, alors que dans d’autres frameworks, le sous-classement est utilisé.
Par exemple, dans Java, vous utilisez beaucoup les instances de *Listener
anonymes et, dans .NET, vous utilisez beaucoup vos sous-classes EventArgs
. Dans Cocoa, vous ne le faites pas non plus - l'action cible est utilisée à la place.
Vous devez généralement utiliser la fonctionnalité Propriétés déclarées d'Objective-C 2.0 pour toutes vos propriétés. S'ils ne sont pas publics, ajoutez-les dans une extension de classe. L'utilisation de propriétés déclarées clarifie immédiatement la sémantique de la gestion de la mémoire et facilite la vérification de votre méthode dealloc. Si vous regroupez vos déclarations de propriétés, vous pouvez les analyser rapidement et les comparer à la mise en œuvre de votre méthode dealloc.
Vous devriez réfléchir sérieusement avant de ne pas marquer les propriétés comme étant "nonatomiques". Comme Le Guide du langage de programmation Objective C note, les propriétés sont atomiques par défaut et entraînent une surcharge considérable. De plus, le simple fait de 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 n'implémentez pas vos propres méthodes d'accesseur (plutôt que de les synthétiser), vous devez les implémenter de manière atomique.
Comme cette question note, les messages à nil
sont valides dans Objective-C. Bien que cela soit souvent un avantage - conduisant à un code plus propre et plus naturel - la fonctionnalité peut parfois conduire à des bogues particuliers et difficiles à dépister si vous obtenez une valeur nil
lorsque vous ne vous y attendiez pas .
Utilisez NSAssert et ses amis. J'utilise nil comme objet valide tout le temps ... En particulier, l'envoi de messages à nil 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 permet de détecter facilement les problèmes.
Simple mais souvent oublié. Selon spec:
En général, les méthodes de classes différentes ayant le même sélecteur (le même nom) doivent également partager les mêmes types de retour et d'argument. Cette contrainte est imposée par le compilateur pour permettre la liaison dynamique.
dans ce cas, tous les mêmes sélecteurs nommés, même dans des classes différentes, seront considérés comme ayant des types de retour/argument identiques. Voici un exemple simple.
@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;
}
Si vous utilisez Leopard (Mac OS X 10.5) ou une version ultérieure, vous pouvez utiliser l'application Instruments pour rechercher et suivre les fuites de mémoire. Après avoir créé votre programme dans Xcode, sélectionnez Exécuter> Démarrer avec Performance Tool> Fuites.
Même si votre application ne montre aucune fuite, vous pouvez conserver des objets trop longtemps. Dans Instruments, vous pouvez utiliser l'instrument ObjectAlloc pour cela. Sélectionnez l'instrument ObjectAlloc dans votre document Instruments et affichez les détails de l'instrument (s'il ne s'affiche pas déjà) en sélectionnant Affichage> Détail (une coche devrait le cocher). Sous "Durée de vie des allocations" dans le détail d'ObjectAlloc, assurez-vous de sélectionner le bouton d'option en regard de "Créé & toujours vivant".
Maintenant, chaque fois que vous arrêtez d'enregistrer votre application, la sélection de l'outil ObjectAlloc vous indiquera le nombre de références à chaque objet encore vivant de votre application dans la colonne "# Net". Assurez-vous que vous ne regardez pas seulement vos propres classes, mais également celles des objets de niveau supérieur de vos fichiers NIB. Par exemple, si vous n'avez aucune fenêtre à l'écran et que vous voyez des références à une fenêtre Windows toujours vivante, vous ne l'avez peut-être pas publiée dans votre code.
Nettoyer à dealloc.
C'est l'une des choses les plus faciles à oublier - en particulier. lors du codage à 150 mph. Toujours, toujours, toujours nettoyer vos attributs/variables membres dans dealloc.
J'aime utiliser les attributs Objc 2 - avec la nouvelle notation par points -, ce qui rend le nettoyage sans douleur. Souvent aussi simple que:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
Cela s'occupera de la publication pour vous et définira l'attribut sur NULL (ce que je considère comme une programmation défensive - au cas où une autre méthode plus loin dans dealloc accède à nouveau à la variable membre - rare mais pourrait arriver).
Avec GC activé dans la version 10.5, cela n'est plus tellement nécessaire - mais vous devrez peut-être nettoyer les autres ressources que vous créez, vous pouvez le faire à l'aide de la méthode de finalisation.
Tous ces commentaires sont excellents, mais je suis vraiment surpris que personne ne soit mentionné Guide de style de Google Objective-C publié il y a quelque temps. Je pense qu'ils ont fait un travail très minutieux.
En outre, sujet semi-lié (avec de la place pour plus de réponses!):
Quels sont ces petits trucs et astuces Xcode que vous souhaiteriez connaître il y a 2 ans? .
N'oubliez pas que NSWindowController et NSViewController vont publier les objets de niveau supérieur des fichiers NIB qu'ils gèrent.
Si vous chargez manuellement un fichier NIB, vous êtes responsable de la libération des objets de niveau supérieur de cette NIB lorsque vous en avez terminé.
Une solution plutôt évidente pour un débutant: utilisez la fonctionnalité d'indentation automatique de Xcode pour votre code. Même si vous copiez/collez à partir d'une autre source, une fois le code collé, vous pouvez sélectionner le bloc de code entier, cliquer dessus avec le bouton droit de la souris, puis choisir l'option pour réindenter tout le contenu de ce bloc.
En fait, Xcode analysera cette section et la mettra en retrait à l'aide de crochets, de boucles, etc. C'est beaucoup plus efficace que d'appuyer sur la barre d'espace ou la touche de tabulation pour chaque ligne.
Variables et propriétés
1/Garder vos en-têtes propres, masquer la mise en œuvre
N'incluez pas de variables d'instance dans votre en-tête. Variables privées placées dans la continuation de la classe en tant que propriétés. Les variables publiques sont déclarées comme propriétés publiques dans votre en-tête. S'il doit seulement être lu, déclarez-le en lecture seule et écrasez-le en lecture-écriture dans la continutation de classe. En gros, je n’utilise pas du tout de variables, mais seulement des propriétés.
2/Donnez à vos propriétés un nom de variable autre que celui par défaut, exemple:
@synthesize property = property_;
Raison 1: Vous allez attraper les erreurs causées par l'oubli de "soi". lors de l'attribution de la propriété. Raison n ° 2: d'après mes expériences, l'analyseur de fuite dans Instruments a des problèmes pour détecter une propriété qui fuit avec un nom par défaut.
3/Ne jamais utiliser retenir ou libérer directement sur les propriétés (ou seulement dans des situations très exceptionnelles). Dans votre dealloc, attribuez-leur un zéro. Les propriétés de conservation sont destinées à gérer la conservation/libération par elles-mêmes. Vous ne savez jamais si un passeur n'est pas, par exemple, ajouter ou supprimer des observateurs. Vous devez utiliser la variable directement uniquement à l'intérieur de ses paramètres de lecture et d'acquisition.
Vues
1/Mettez chaque définition de vue dans un xib, si vous le pouvez (à l'exception du contenu dynamique et des paramètres de calque). Cela permet de gagner du temps (c'est plus facile que d'écrire du code), de le changer facilement et de garder votre code propre.
2/N'essayez pas d'optimiser les vues en diminuant le nombre de vues. Ne créez pas UIImageView dans votre code au lieu de xib simplement parce que vous souhaitez y ajouter des sous-vues. Utilisez plutôt UIImageView comme arrière-plan. Le framework de vues peut gérer des centaines de vues sans problèmes.
3/Les IBOutlets ne doivent pas toujours être conservés (ou forts). Notez que la plupart de vos IBOutlets font partie de votre hiérarchie de vues et sont donc implicitement conservés.
4/Libérez tous les IBOutlets dans viewDidUnload
5/Appelez viewDidUnload depuis votre méthode dealloc. Il n'est pas appelé implicitement.
mémoire
1/Libération automatique des objets lors de leur création. De nombreux bogues sont causés par le déplacement de votre appel de publication dans une branche if-else ou après une instruction return. La libération au lieu de autorelease ne doit être utilisée que dans des situations exceptionnelles - par exemple, lorsque vous attendez un runloop et que vous ne voulez pas que votre objet soit auto-libéré trop tôt.
2/Même si vous utilisez le comptage de référence automatique, vous devez comprendre parfaitement le fonctionnement des méthodes de conservation-libération. L'utilisation manuelle de la retenue-libération n'est pas plus compliquée qu'ARC, dans les deux cas, vous devez vous occuper des fuites et des cycles de retenue. Pensez à utiliser la rétention manuelle manuellement sur les grands projets ou les hiérarchies d'objets complexes.
Commentaires
1/Faites votre code autodocumented. Chaque nom de variable et nom de méthode doit indiquer ce qu’il fait. Si le code est écrit correctement (vous avez besoin de beaucoup de pratique dans ce domaine), vous n'aurez besoin d'aucun commentaire de code (différent de celui de la documentation). Les algorithmes peuvent être compliqués mais le code doit toujours être simple.
2/Parfois, vous aurez besoin d'un commentaire. Habituellement décrire un comportement de code non apparent ou un hack. Si vous sentez que vous devez écrire un commentaire, essayez d’abord de réécrire le code pour qu’il soit plus simple et sans commentaires.
indentation
1/N'augmentez pas trop l'indentation. La plupart de votre code de méthode doit être mis en retrait au niveau de la méthode. Les blocs imbriqués (si, pour, etc.) diminuent la lisibilité. Si vous avez trois blocs imbriqués, vous devez essayer de placer les blocs internes dans une méthode distincte. Quatre blocs imbriqués ou plus ne doivent jamais être utilisés. Si la majeure partie du code de votre méthode est à l'intérieur d'un if, annulez la condition if, par exemple:
if (self) {
//... long initialization code ...
}
return self;
if (!self) {
return nil;
}
//... long initialization code ...
return self;
Comprendre le code C, principalement les structures C
Notez que Obj-C est seulement une couche légère OOP sur le langage C. Vous devez comprendre le fonctionnement des structures de code de base en C (énumérations, structures, tableaux, pointeurs, etc.). Exemple:
view.frame = CGRectMake(view.frame.Origin.x, view.frame.Origin.y, view.frame.size.width, view.frame.size.height + 20);
est le même que:
CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;
et beaucoup d'autres
Conservez votre propre document sur les normes de codage et mettez-le à jour souvent. Essayez d'apprendre de vos insectes. Comprenez pourquoi un bogue a été créé et essayez de l'éviter en utilisant des normes de codage.
Nos normes de codage ont actuellement une vingtaine de pages, un mélange de Java normes de codage, de normes Google Obj-C/C++ et de nos propres ajouts. Documentez votre code, utilisez l'indentation standard, les espaces et les lignes vides aux bons endroits, etc.
Activez tous les avertissements GCC, puis désactivez ceux qui sont régulièrement causés par les en-têtes d’Apple afin de réduire le bruit.
Exécutez également l'analyse statique de Clang fréquemment; vous pouvez l'activer pour toutes les générations via le paramètre de construction "Run Static Analyzer".
Ecrivez des tests unitaires et exécutez-les avec chaque build.
Je sais que j'ai négligé cela lors de ma première participation à la programmation de Cocoa.
Assurez-vous de bien comprendre les responsabilités de la gestion de la mémoire en ce qui concerne les fichiers NIB. Vous êtes responsable de la libération des objets de niveau supérieur dans tout fichier NIB que vous chargez. Lire Documentation Apple sur le sujet.
Soyez plus fonctionnel.
Objective-C est un langage orienté objet, mais le framework Cocoa est sensible au style fonctionnel et est conçu dans de nombreux cas.
Il y a séparation de la mutabilité. Utilisez des classes immuables en tant qu'objets primaires et des objets mutables en tant qu'objets secondaires. Par exemple, utilisez principalement NSArray et NSMutableArray uniquement lorsque vous en avez besoin.
Il y a des fonctions pures. Pas si nombreux, achetez beaucoup d'API du framework sont conçues comme des fonctions pures. Regardez des fonctions telles que CGRectMake()
ou CGAffineTransformMake()
. De toute évidence, la forme du pointeur semble plus efficace. Cependant, les arguments indirects avec les pointeurs ne peuvent pas offrir d’effets secondaires. Concevoir des structures purement autant que possible. Séparez même les objets d'état. Utilisez -copy
au lieu de -retain
lorsque vous transmettez une valeur à un autre objet. Parce que l'état partagé peut influencer la mutation pour que la valeur de l'autre objet soit silencieuse. Donc, ne peut pas être sans effets secondaires. Si vous avez une valeur from external from object, copiez-la. Il est donc également important de concevoir un état partagé aussi minimal que possible.
Cependant, n'ayez pas peur d'utiliser des fonctions impures aussi.
Il y a évaluation paresseuse. Voir quelque chose comme la propriété -[UIViewController view]
. La vue ne sera pas créée lors de la création de l'objet. Il sera créé lorsque l'appelant lit la propriété view
à la première fois. UIImage
ne sera pas chargé avant son dessin. Il existe de nombreuses implémentations comme cette conception. Ce type de conceptions est très utile pour la gestion des ressources, mais si vous ne connaissez pas le concept d'évaluation paresseuse, il n'est pas facile de comprendre leur comportement.
Il y a fermeture. Utilisez autant que possible les blocs en C. Cela simplifiera grandement votre vie. Mais lisez encore une fois sur la gestion de la mémoire de blocs avant de l'utiliser.
Il y a GC semi-automatique. NSAutoreleasePool. Utilisez -autorelease
primaire. Utilisez le manuel -retain/-release
secondaire lorsque vous en avez vraiment besoin. (ex: optimisation de la mémoire, suppression explicite de ressources)
Les exemples fournis par Apple que j'ai vus traitaient le délégué de l'application comme un magasin de données global, un gestionnaire de données en quelque sorte. C'est imprudent. Créez un singleton et installez-le peut-être dans le délégué de l'application, mais évitez d'utiliser le délégué de l'application comme autre chose que la gestion des événements au niveau de l'application. Je soutiens chaleureusement les recommandations de cette entrée de blog . Ce fil m'a prévenu.
Libère uniquement une méthode propriété dans dealloc. Si vous voulez libérer la mémoire que la propriété est en train de contenir, définissez-la simplement comme nil:
self.<property> = nil;
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass