Je connais le HIG (ce qui est assez pratique!), Mais quelles pratiques de programmation utilisez-vous lors de l'écriture d'Objective-C, et plus précisément lors de l'utilisation de Cocoa (ou CocoaTouch).
Je connais le HIG (ce qui est assez pratique!), Mais quelles pratiques de programmation utilisez-vous lors de l'écriture d'Objective-C, et plus précisément lors de l'utilisation de Cocoa (ou CocoaTouch).
Réponses:
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 classe "privées". Après tout, si une variable est accessible par d'autres classes, ne devrait-elle pas y avoir de 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 auxquelles les étrangers ne devraient pas se soucier? Le 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 pris la décision de mettre dealloc en haut du fichier .m, juste en dessous des directives @synthesize. Ce que vous traitez ne devrait-il pas être en haut de la liste des choses auxquelles vous voulez penser dans une classe? Cela est particulièrement vrai dans un environnement comme l'iPhone.
3.5) Dans les cellules du tableau, rendez chaque élément (y compris la cellule elle-même) opaque pour les performances. Cela signifie définir la couleur d'arrière-plan appropriée dans tout.
3.6) Lorsque vous utilisez une connexion NSURLConnection, en règle générale, vous souhaiterez peut-être implémenter la méthode déléguée:
- (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 souhaiterez 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.
Également intéressants, voici quelques bons conseils spécifiques à l'iPhone de Joseph Mattiello (reçus dans une liste de diffusion iPhone). Il y en a plus, mais ce sont les plus utiles que je pensais (notez que quelques bits ont maintenant été légèrement modifiés par rapport à l'original pour inclure les détails offerts dans les réponses):
4) N'utilisez la double précision que si vous le devez, comme lorsque vous travaillez avec CoreLocation. Assurez-vous de terminer vos constantes en «f» pour que gcc les stocke sous forme de flottants.
float val = someFloat * 2.2f;
Ceci est surtout important quand il someFloat
peut s'agir d'un double, vous n'avez pas besoin des calculs 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 dans le matériel sur les iPhones, il peut encore prendre plus de temps pour effectuer une arithmétique à double précision par opposition à la simple précision. Références:
Sur les téléphones plus anciens, les calculs fonctionnent censément à la même vitesse, mais vous pouvez avoir plus de composants de simple précision dans les registres que de 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, du 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 moins gonflé et plus efficace en mémoire lorsqu'il est défini sur non anatomique.
6) SQLite peut être un moyen très, 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 les E / S disque. Évitez de nombreuses petites écritures en envoyant BEGIN;
et COMMIT;
entre de gros blocs. Nous utilisons par exemple un temporisateur de 2 secondes qui se réinitialise à chaque nouvelle soumission. À son expiration, nous envoyons COMMIT; , ce qui fait que toutes vos écritures vont en un seul gros morceau. SQLite stocke les données de transaction sur le disque et cette opération de début / fin évite la création de nombreux fichiers de transaction, en regroupant toutes les transactions dans un seul fichier.
En outre, SQL bloquera votre interface graphique si elle se trouve sur votre thread principal. Si vous avez une requête très longue, c'est une bonne idée de stocker vos requêtes en tant qu'objets statiques et d'exécuter votre SQL sur un thread séparé. Assurez-vous d'envelopper tout ce qui modifie la base de données pour les chaînes de requête en @synchronize() {}
blocs. Pour les requêtes courtes, laissez simplement les choses sur le fil principal pour plus de commodité.
Plus de conseils d'optimisation SQLite sont ici, bien que le document semble obsolète, de nombreux points sont probablement encore bons;
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Lorsque les méthodes ou les fonctions prennent un argument de chaîne de format, vous devez vous assurer que vous avez le contrôle sur le contenu de la chaîne de format.
Par exemple, lors de la journalisation de chaînes, il est tentant de passer la variable chaîne comme seul argument à NSLog
:
NSString *aString = // get a string from somewhere;
NSLog(aString);
Le problème avec cela est que la chaîne peut contenir des caractères qui sont interprétés comme des chaînes de format. Cela peut entraîner une sortie erronée, des plantages et des problèmes de sécurité. Au lieu de cela, vous devez remplacer la variable chaîne dans une chaîne de format:
NSLog(@"%@", aString);
Utilisez les conventions et la terminologie de nommage et de mise en forme Cocoa standard plutôt que tout ce à quoi vous êtes habitué dans un autre environnement. Là existe de nombreux développeurs Cocoa, et lorsqu'un autre d'entre eux commencera à travailler avec votre code, il sera beaucoup plus accessible s'il ressemble et se sent similaire à un autre code Cocoa.
Exemples de choses à faire et à ne pas faire:
id m_something;
dans l'interface d'un objet et appelez-le une variable ou un champ membre ; utiliser something
ou _something
pour son nom et l'appeler un variable d'instance .-getSomething
; le nom Cocoa correct est juste -something
.-something:
; ça devrait être-setSomething:
-[NSObject performSelector:withObject:]
pas le cas NSObject::performSelector
.Quoi que vous fassiez d'autre, n'utilisez pas la notation hongroise de style Win16 / Win32. Même Microsoft a renoncé à cela avec le passage à la plate-forme .NET.
Historiquement, la gestion de la mémoire des prises a été médiocre. La meilleure pratique actuelle consiste à déclarer des prises en tant que propriétés:
@interface MyClass :NSObject {
NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end
L'utilisation des propriétés rend la sémantique de gestion de la mémoire claire; il fournit également un modèle cohérent si vous utilisez la synthèse de variables d'instance.
REMARQUE: sous Xcode 4, cela est désormais intégré à l'EDI.
Vous utilisez l' Analyseur statique Clang pour - sans surprise - analyser votre code C et Objective-C (pas encore de C ++) sur Mac OS X 10.5. Il est trivial d'installer et d'utiliser:
cd
vers votre répertoire de projet.scan-build -k -V xcodebuild
.(Il existe des contraintes supplémentaires, etc., en particulier, vous devez 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 à quoi cela se résume.)
L'analyseur produit ensuite pour vous un ensemble de pages Web qui montre la gestion probable de la mémoire et d'autres problèmes de base que le compilateur est incapable de détecter.
C'est subtil mais pratique. Si vous vous passez en tant que délégué à un autre objet, réinitialisez le délégué de cet objet avant vous dealloc
.
- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}
En faisant cela, vous vous assurez qu'aucune autre méthode déléguée ne sera envoyée. Alors que vous êtes sur le point de dealloc
disparaître dans l'éther, vous voulez vous assurer que rien ne peut plus vous envoyer de messages par accident. Rappelez-vous que self.someObject pourrait être conservé par un autre objet (il pourrait s'agir d'un singleton ou du pool de libération automatique ou autre) et jusqu'à ce que vous lui disiez "arrêtez de m'envoyer des messages!", Il pense que votre objet sur le point d'être libéré est un jeu équitable.
Prendre cette habitude vous évitera de nombreux accidents étranges qui sont difficiles à déboguer.
Le même principe s'applique à l'observation des valeurs clés, ainsi qu'aux NSNotifications.
Éditer:
Encore plus défensif, changez:
self.someObject.delegate = NULL;
dans:
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
. Ils sont exactement les mêmes sauf que nil
c'est un id
et NULL
est un void *
. Votre déclaration n'est pas vraie.
@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 d'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 @interface de la classe principale"
Ils font donc partie de la classe réelle - et NON d'une catégorie (privée) en plus de la classe. Différence subtile mais importante.
()
place de (Private)
(ou d'un autre nom de catégorie): vous pouvez redéclarer des propriétés en lecture-écriture alors qu'au public elles ne sont qu'en lecture seule. :)
Étant donné que vous (1) n'avez généralement pas de contrôle direct sur leur durée de vie, les objets libérés automatiquement peuvent persister relativement longtemps et augmenter inutilement l'empreinte mémoire de votre application. Alors que sur le bureau, cela peut avoir peu de conséquences, sur des plateformes plus limitées, cela peut être un problème important. Par conséquent, sur toutes les plates-formes, et en particulier sur les plates-formes plus contraintes, il est considéré comme la meilleure pratique pour éviter d'utiliser des méthodes qui conduiraient à des objets à libération automatique et vous êtes plutôt encouragé à utiliser le modèle alloc / init.
Ainsi, plutôt que:
aVariable = [AClass convenienceMethod];
si possible, vous devez utiliser à la place:
aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];
Lorsque vous écrivez vos propres méthodes qui retournent un objet nouvellement créé, vous pouvez profiter de la convention de dénomination de Cocoa 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;
}
vous pourriez écrire:
- (MyClass *)newInstance {
MyClass *instance = [[self alloc] init];
// configure instance
return instance;
}
Comme le nom de la méthode commence par "nouveau", les consommateurs de votre API savent qu'ils sont responsables de la libération de l'objet reçu (voir, par exemple, la newObject
méthode NSObjectController ).
(1) Vous pouvez prendre le contrôle en utilisant vos propres pools de libération automatique locaux. Pour en savoir plus à ce sujet, voir Pools de libération automatique .
NSAutoreleasePool
. Mais seulement après avoir confirmé que c'est vraiment un problème. Optimisation prématurée et tout ça ...
Certains d'entre eux ont déjà été mentionnés, mais voici ce que je peux penser du haut de ma tête:
#pragma mark [section]
.Habituellement, je regroupe par mes propres méthodes, les remplacements de chaque sous-classe et toute information ou protocole formel. Cela rend beaucoup plus facile de passer exactement à ce que je recherche. Sur le même sujet, regroupez des méthodes similaires (comme les méthodes déléguées d'une vue de table), ne les collez pas n'importe où.#define
ça va, ou mettre en cache un tableau au lieu de le trier chaque fois que les données sont nécessaires. Il y a beaucoup de choses que je pourrais dire à ce sujet, mais l'essentiel est de ne pas écrire de code tant que vous n'en avez pas besoin ou que le profileur ne vous le dit pas. Cela rend les choses beaucoup plus faciles à entretenir à long terme.NSLog( @"stub" )
intérieur, ou comme vous voulez garder une trace des choses.Finish what you start
vous pouvez également utiliser // TODO:
pour marquer le code pour l'achèvement qui apparaîtra dans la liste déroulante.
Écrire 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 de l'interface utilisateur, vous pouvez généralement vérifier que les choses sont connectées comme elles devraient être et avoir confiance qu'elles fonctionneront lorsqu'elles seront utilisées. Et vous pouvez configurer facilement l'état et invoquer des méthodes de délégué pour les tester.
Vous n'avez pas non plus de visibilité sur les méthodes publiques, protégées ou privées, 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
copy
, mutableCopy
, new
ou retain
.
N'écrivez pas Objective-C comme s'il s'agissait de Java / C # / C ++ / etc.
J'ai vu une fois une équipe habituée à écrire des 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 qui volaient quand tout ce dont ils avaient vraiment besoin était une classe Foo et peut-être un protocole Fooable.
Pour vous assurer de ne pas le faire, vous devez vraiment comprendre les différences de langue. 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 aussi dynamiquement que les méthodes d'instance et peuvent être remplacées dans les sous-classes.
Assurez-vous de marquer la page Debugging Magic . Cela devrait être votre premier arrêt lorsque vous vous cognez la tête contre un mur tout en essayant de trouver la source d'un bug Cocoa.
Par exemple, il vous indiquera comment trouver la méthode où vous avez alloué la mémoire pour la première fois, ce qui provoque des plantages (comme lors de la fermeture d'une application).
Essayez d'éviter ce que j'ai décidé d'appeler Newbiecategoryaholism. Lorsque les nouveaux arrivants à Objective-C découvrent des catégories, ils se déchaînent souvent, 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 rock!" ).
Ne fais pas ça.
Votre code sera plus portable et plus facile à comprendre avec des dizaines de petites méthodes de catégorie saupoudrées sur deux douzaines de classes de base.
La plupart du temps, lorsque vous pensez vraiment avoir besoin d'une méthode de catégorie pour simplifier le code, vous constaterez que vous ne finirez jamais par réutiliser la méthode.
Il y a aussi d'autres dangers, à moins que vous ne nommiez vos méthodes de catégorie (et qui est en plus du ddribin complètement fou?), Il y a une chance qu'Apple, ou un plugin, ou quelque chose d'autre fonctionnant dans votre espace d'adressage définisse également la même catégorie méthode du 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ésistez à sous-classer le monde. Dans Cocoa, beaucoup de choses sont faites par délégation et utilisation du runtime sous-jacent qui, dans d'autres frameworks, se fait par sous-classement.
Par exemple, en Java, vous utilisez beaucoup d'instances de *Listener
sous-classes anonymes et en .NET, vous utilisez EventArgs
beaucoup vos sous-classes. Dans Cocoa, vous ne faites pas non plus - l'action cible est utilisée à la place.
Lorsque vous triez des chaînes à présenter à l'utilisateur, vous ne devez pas utiliser la compare:
méthode simple . 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 Rechercher, comparer et trier des chaînes .
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 rend la sémantique de gestion de la mémoire immédiatement claire et vous permet de vérifier plus facilement votre méthode dealloc - si vous regroupez vos déclarations de propriété, vous pouvez les analyser rapidement et comparer avec l'implémentation de votre méthode dealloc.
Vous devez bien réfléchir avant de ne pas marquer les propriétés comme «non anatomiques». Comme le note le Guide du langage de programmation Objective C , les propriétés sont atomiques par défaut et entraînent des frais généraux considérables. 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 «non anatomique» et implémentez vos propres méthodes d'accesseur (plutôt que de les synthétiser), vous devez les implémenter de manière atomique.
Comme le note cette question , 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 à localiser si vous obtenez une nil
valeur alors que vous ne vous y attendiez pas.
Utilisez NSAssert et vos amis. J'utilise nil comme objet valide tout le temps ... surtout l'envoi de messages à nil est parfaitement valide en 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 les spécifications:
En général, les méthodes de différentes classes qui ont 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 s'ils sont 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 l'outil de performance> Fuites.
Même si votre application ne présente aucune fuite, vous gardez peut-être 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 n'est pas déjà affiché) en choisissant Affichage> Détail (il doit avoir une coche à côté). Sous "Allocation Lifespan" dans le détail ObjectAlloc, assurez-vous de sélectionner le bouton radio à côté de "Created & Still Living".
Désormais, chaque fois que vous arrêtez d'enregistrer votre application, la sélection de l'outil ObjectAlloc vous montrera le nombre de références à chaque objet encore vivant dans votre application dans la colonne "# Net". Assurez-vous de regarder non seulement vos propres classes, mais aussi les classes 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 NSWindow encore en vie, vous ne l'avez peut-être pas publiée dans votre code.
Nettoyer dans 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 - donc cela rend le nettoyage indolore. Souvent aussi simple que:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
Cela prendra soin de la publication pour vous et définira l'attribut sur NULL (que je considère comme une programmation défensive - au cas où une autre méthode plus bas dans dealloc accède à nouveau à la variable membre - rare mais pourrait arriver).
Avec GC activé dans 10.5, cela n'est plus nécessaire - mais vous devrez peut-être nettoyer les autres ressources que vous créez, vous pouvez le faire dans la méthode finalize à la place.
-init
et les -dealloc
méthodes peut être trouvée ici: mikeash.com/?page=pyblog/…
Tous ces commentaires sont excellents, mais je suis vraiment surpris que personne n'ait mentionné le guide de style Objective-C de Google qui a été publié il y a quelque temps. Je pense qu'ils ont fait un travail très approfondi.
Aussi, sujet semi-connexe (avec de la place pour plus de réponses!):
Quels sont ces petits trucs et astuces Xcode que vous aimeriez connaître il y a environ 2 ans? .
N'oubliez pas que NSWindowController et NSViewController libéreront les objets de niveau supérieur des fichiers NIB qu'ils gouvernent.
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é avec eux.
Une utilisation assez évidente pour un débutant: utilisez la fonction d'indentation automatique de Xcode pour votre code. Même si vous copiez / collez à partir d'une autre source, une fois que vous avez collé le code, vous pouvez sélectionner tout le bloc de code, cliquer avec le bouton droit sur celui-ci, puis choisir l'option pour ré-indenter tout dans ce bloc.
Xcode va réellement analyser cette section et l'indenter en fonction des crochets, des boucles, etc. C'est beaucoup plus efficace que d'appuyer sur la barre d'espace ou la touche de tabulation pour chaque ligne.
Je sais que j'ai ignoré cela lors de la première entrée dans la programmation Cocoa.
Assurez-vous de bien comprendre les responsabilités de gestion de la mémoire concernant les fichiers NIB. Vous êtes responsable de la libération des objets de niveau supérieur dans tout fichier NIB que vous chargez. Lisez la documentation d'Apple sur le sujet.
Activez tous les avertissements GCC, puis désactivez ceux qui sont régulièrement causés par les en-têtes d'Apple pour réduire le bruit.
Exécutez également fréquemment l'analyse statique Clang; vous pouvez l'activer pour toutes les générations via le paramètre de génération "Run Static Analyzer".
Écrivez des tests unitaires et exécutez-les avec chaque build.
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 mises en continuation de classe en tant que propriétés. Les variables publiques se déclarent comme propriétés publiques dans votre en-tête. S'il ne doit être lu que, déclarez-le en lecture seule et écrasez-le en lecture-écriture dans la continuation de classe. En gros, je n'utilise pas du tout de variables, seulement des propriétés.
2 / Donnez à vos propriétés un nom de variable non par défaut, exemple:
@synthesize property = property_;
Raison 1: vous allez détecter les erreurs causées par l'oubli de «soi». lors de l'attribution de la propriété. Raison 2: D'après mes expériences, Leak Analyzer in Instruments a des problèmes pour détecter la fuite de propriété avec le nom par défaut.
3 / Ne jamais utiliser de conserver ou de libérer directement sur les propriétés (ou seulement dans des situations très exceptionnelles). Dans votre dealloc, attribuez-leur simplement un zéro. Les propriétés de conservation sont destinées à gérer la conservation / libération par elles-mêmes. On ne sait jamais si un poseur ne fait pas, par exemple, l'ajout ou la suppression d'observateurs. Vous ne devez utiliser la variable directement qu'à l'intérieur de son setter et de son getter.
Vues
1 / Mettez chaque définition de vue dans un fichier xib, si vous le pouvez (l'exception est généralement le contenu dynamique et les paramètres de calque). Il fait gagner du temps (c'est plus facile que d'écrire du code), il est facile à changer et il garde 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 cadre de vue peut gérer des centaines de vues sans problème.
3 / Les prises IBO ne doivent pas toujours être conservées (ou résistantes). Notez que la plupart de vos IBOutlets font partie de votre hiérarchie de vues et sont donc implicitement conservées.
4 / Libérez tous les IBOutlets dans viewDidUnload
5 / Appelez viewDidUnload à partir de votre méthode dealloc. Il n'est pas implicitement appelé.
Mémoire
1 / Libérez automatiquement les objets lorsque vous les créez. De nombreux bogues sont causés par le déplacement de votre appel de version dans une branche if-else ou après une déclaration de retour. La libération au lieu de la libération automatique ne doit être utilisée que dans des situations exceptionnelles - par exemple lorsque vous attendez une boucle d'exécution et que vous ne voulez pas que votre objet soit libéré automatiquement trop tôt.
2 / Même si vous utilisez le comptage de référence automatique, vous devez parfaitement comprendre le fonctionnement des méthodes de conservation-libération. L'utilisation manuelle de la libération-retenue n'est pas plus compliquée que l'ARC, dans les deux cas, vous devez faire attention aux fuites et aux cycles de rétention. Pensez à utiliser manuellement la version retenue sur les grands projets ou les hiérarchies d'objets complexes.
commentaires
1 / Rendez votre code autodocumenté. 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 pas besoin de commentaires de code (pas les mêmes que les commentaires de documentation). Les algorithmes peuvent être compliqués mais le code doit toujours être simple.
2 / Parfois, vous aurez besoin d'un commentaire. Généralement pour décrire un comportement de code non apparent ou un hack. Si vous pensez que vous devez écrire un commentaire, essayez d'abord de réécrire le code pour être plus simple et sans avoir besoin de commentaires.
Échancrure
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.) réduisent la lisibilité. Si vous avez trois blocs imbriqués, vous devez essayer de placer les blocs internes dans une méthode distincte. Quatre blocs ou plus imbriqués ne doivent jamais être utilisés. Si la majeure partie de votre code de méthode se trouve à 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 n'est qu'une couche OOP légère 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 plus
Conservez votre propre document de normes de codage et mettez-le régulièrement à jour. Essayez d'apprendre de vos bugs. Comprenez pourquoi un bogue a été créé et essayez de l'éviter en utilisant des normes de codage.
Nos normes de codage ont actuellement environ 20 pages, un mélange de normes de codage Java, de normes Google Obj-C / C ++ et de nos propres ajouts. Documentez votre code, utilisez une indentation standard standard, des espaces blancs et des lignes vides aux bons endroits, etc.
Soyez plus fonctionnel .
Objective-C est un langage orienté objet, mais Cocoa Framework est sensible au style fonctionnel et est conçu dans de nombreux cas comme un style fonctionnel.
Il y a séparation de mutabilité. Utilisez des classes immuables comme objet principal et mutable comme secondaire. Par exemple, utilisez principalement NSArray et n'utilisez NSMutableArray que lorsque vous en avez besoin.
Il y a des fonctions pures. Pas tellement, acheter de nombreuses API de framework sont conçues comme une fonction pure. Regardez des fonctions telles que CGRectMake()
ou CGAffineTransformMake()
. De toute évidence, la forme du pointeur semble plus efficace. Cependant, l'argument indirect avec des pointeurs ne peut pas offrir sans effet secondaire. Concevez les structures autant que possible. Séparez les objets d'état pairs. Utilisez -copy
au lieu de -retain
lors du passage d'une valeur à un autre objet. Parce que l'état partagé peut influencer la mutation en valeur dans un autre objet en silence. Ne peut donc pas être exempt d'effets secondaires. Si vous avez une valeur de 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 également des fonctions impures.
Il y a une évaluation paresseuse. Voir quelque chose comme une -[UIViewController view]
propriété. La vue ne sera pas créée lors de la création de l'objet. Il sera créé lors view
de la première lecture de la propriété de l' appelant . UIImage
ne sera pas chargé jusqu'à ce qu'il soit réellement 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 de l'évaluation paresseuse, il n'est pas facile de comprendre leur comportement.
Il y a fermeture. Utilisez autant que possible les blocs C. Cela vous simplifiera grandement la vie. Mais lisez encore une fois sur la gestion de la mémoire de bloc avant de l'utiliser.
Il existe un GC semi-automatique. NSAutoreleasePool. Utilisez -autorelease
primaire. Utilisez le -retain/-release
secondaire manuel lorsque vous en avez vraiment besoin. (ex: optimisation de la mémoire, suppression explicite des ressources)
autorelease
que la mémoire sera généralement conservée plus longtemps, et le manuel retain/release
peut réduire la consommation de mémoire dans le cas. Cependant, cela devrait être un guide pour l'optimisation des cas spéciaux (même si vous vous sentez toujours!), Ne peut pas être la raison de généraliser l'optimisation prématurée en tant que pratique . Et en fait, votre suggestion n'est pas opposée à moi. Je l'ai mentionné comme cas de besoin réel :)