Quelles sont les meilleures pratiques que vous utilisez lorsque vous écrivez Objective-C et Cocoa? [fermé]

StackOverflow https://stackoverflow.com/questions/155964

Question

Je connais les HIG (ce qui est assez pratique!), mais quelles pratiques de programmation utilisez-vous pour écrire Objective-C, et plus particulièrement pour utiliser Cocoa (ou CocoaTouch).

Était-ce utile?

La solution

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

1) Avec l'avènement de propriétés, je n'utilise plus " _ " préfixer "privé" variables de classe. 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 l'omettre.

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 suit:

#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 tel que 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 d'arrière-plan appropriée pour tout.

3.6) Lorsque vous utilisez NSURLConnection, vous souhaiterez peut-être en règle générale 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 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 sur les iPhone. Il y en a d'autres, 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' sur le 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 peut 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 simple précision finira par être plus rapide.

5) Définissez vos propriétés comme non atomique . 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'ont probablement pas besoin de vous inquiéter à ce sujet et le code est beaucoup moins volumineux et utilise plus efficacement 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 les petites écritures en envoyant BEGIN; et COMMIT; entre des blocs volumineux. 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. Cette opération de début et de fin permet d’éviter 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 brèves, laissez les éléments sur le fil principal pour plus de commodité.

D'autres astuces d'optimisation SQLite sont disponibles, bien que le document semble obsolète, de nombreux points sont probablement toujours valables;

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

Autres conseils

N'utilisez pas de chaînes inconnues comme chaînes de format

Lorsque des méthodes ou des fonctions utilisent un argument de chaîne de format, assurez-vous de contrôler le contenu de la chaîne de format.

Par exemple, lors de la journalisation des chaînes, il est tentant de transmettre la variable chaîne comme unique argument de 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 devez remplacer la variable chaîne par 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 tout ce à quoi vous êtes habitué depuis un autre environnement. Il y a beaucoup de développeurs Cocoa, et lorsqu'un autre d'entre eux commencera à travailler avec votre code, ce sera beaucoup plus abordable s'il ressemble à un autre code Cocoa et se sent comme tel.

Exemples de choses à faire et à ne pas faire:

  • Ne déclarez pas id m_something; dans l'interface d'un objet et appelez-le une variable membre ou un champ ; utilisez quelque chose ou _something pour son nom et appelez-le une variable d'instance .
  • Ne nommez pas un getter -getSomething ; le bon nom de cacao est juste -quelque chose .
  • Ne nommez pas un séparateur -quelquechose: ; ce devrait être -setSomething:
  • Le nom de la méthode est intercalé avec les arguments et inclut les deux points; c'est - [NSObject performSelector: withObject:] , pas NSObject :: performSelector .
  • Utilisez inter-caps (CamelCase) dans les noms de méthodes, paramètres, variables, noms de classes, etc. plutôt que sous-barres (underscores).
  • Les noms de classe commencent par une lettre majuscule, les noms de variable et de méthode par 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 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 rend la sémantique de la gestion de la mémoire claire; il fournit également un motif cohérent si vous utilisez la synthèse de variable d’instance.

Utiliser l'analyseur statique LLVM / Clang

NOTE: Sous Xcode 4, ceci est maintenant intégré à l'EDI.

Vous utilisez Clang Static Analyzer pour analyser votre C et vos objectifs sans surprise. -C code (pas encore C ++) sur Mac OS X 10.5. C'est simple à installer et à utiliser:

  1. Téléchargez la dernière version à partir de cette page .
  2. A partir de la ligne de commande, cd dans le répertoire de votre projet.
  3. Exécuter scan-build -k -V xcodebuild .

(Il existe certaines contraintes supplémentaires, etc., vous devez notamment analyser un projet dans sa configuration "Debug" - voir http://clang.llvm.org/StaticAnalysisUsage.html pour plus de détails - mais c'est à peu près tout ce dont il s'agit.)

L'analyseur génère ensuite pour vous un ensemble de pages Web indiquant la gestion probable de la mémoire et d'autres problèmes basiques que le compilateur est incapable de détecter.

C’est à la fois subtil et 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];
}

Ce faisant, 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 de disparaître dans l’éther, vous voulez vous assurer que rien ne pourra vous envoyer plus de messages par accident. Rappelez-vous que self.omeObject pourrait être retenu par un autre objet (un singleton, un groupe d'auto-libérations ou autre) et jusqu'à ce que vous le lui disiez, "cessez de m'envoyer des messages!", Il pense que vous êtes sur le point de l'être. objet désalloué est un jeu équitable.

Adoptez cette habitude pour éviter de nombreux accidents étranges, difficiles à déboguer.

Le même principe s'applique à Key Value Observation et à NSNotifications.

Modifier:

Encore plus défensif, 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

Utiliser:

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

Nouveautés 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 de classe primaire @interface"

.

Donc, ils font partie de la classe actuelle - et PAS une catégorie (privée) en plus de la classe. Différence subtile mais importante.

Éviter la libération automatique

Comme vous (1) n’avez généralement pas de contrôle direct sur leur durée de vie, les objets auto-lâchés peuvent persister relativement longtemps et augmenter inutilement l’empreinte mémoire de votre application. Sur le bureau, cela peut avoir peu d’importance, mais sur des plateformes 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];

Le cas échéant, vous devriez plutôt utiliser:

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

Lorsque vous écrivez vos propres méthodes renvoyant un objet créé, vous pouvez tirer parti de Convention de dénomination de Cocoa pour signaler au destinataire qu'elle doit être libérée en ajoutant le nom de la méthode au début de la phrase, avec" nouveau ".

Ainsi, au lieu de:

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

vous pouvez écrire:

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

Puisque 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, La méthode newObject de NSObjectController ).

(1) Vous pouvez prendre le contrôle en utilisant vos propres pools de libération automatique locaux. Pour plus d'informations à ce sujet, voir Pools de libération automatique .

Certains d’entre eux ont déjà été mentionnés, mais voici ce à quoi je peux penser:

  • Respectez les règles de nommage du KVO. Même si vous n'utilisez pas le KVO maintenant, l'expérience me permet de constater qu'il est toujours bénéfique à l'avenir. Et si vous utilisez des KVO ou des reliures, vous devez savoir que tout se passe comme prévu. Cela couvre non seulement les méthodes d'accès et les variables d'instance, mais également les relations à plusieurs, la validation, la notification automatique des clés dépendantes, etc.
  • Placez les méthodes privées dans une catégorie. Pas seulement l'interface, mais également la mise en oeuvre. Il est bon d'avoir une certaine distance conceptuelle entre les méthodes privées et non privées. J'inclus tout dans mon fichier .m.
  • Placez les méthodes de threads en arrière-plan dans une catégorie. Comme ci-dessus. J'ai trouvé bon de garder une barrière conceptuelle claire lorsque vous réfléchissez à ce qui est sur le fil principal et à ce qui ne l'est pas.
  • Utiliser #pragma mark [section] . Je groupe généralement par 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ù.
  • Préfixe des méthodes privées & amp; ivars with _. J'aime son apparence et j'ai moins de chances d'utiliser un ivar quand je parle d'une propriété par accident.
  • N'utilisez pas les méthodes / propriétés de mutateur dans init & amp; dealloc. Je n'ai jamais rien eu de grave à cause de cela, mais je peux voir la logique si vous modifiez la méthode pour faire quelque chose qui dépend de l'état de votre objet.
  • Mettez IBOutlets dans les propriétés. Je viens de lire celui-ci ici, mais je vais commencer à le faire. Quels que soient les avantages de la mémoire, cela me semble mieux stylistiquement (du moins pour moi).
  • Évitez d'écrire du code dont vous n'avez absolument pas besoin. Cela couvre vraiment beaucoup de choses, comme créer des ivars lorsqu'un #define fera l'affaire ou mettre en cache un tableau à la place. de le trier à chaque fois que les données sont nécessaires. 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.
  • Terminez ce que vous avez commencé. Avec beaucoup de code à moitié fini, le code de buggy est le moyen le plus rapide de tuer un projet. Si vous avez besoin d’une méthode de stub satisfaisante, indiquez-la simplement en insérant NSLog (@ "stub") à l'intérieur ou par tout autre moyen que vous souhaitez suivre.

Écrire des tests unitaires. Vous pouvez tester un lot 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 avoir confiance qu'ils fonctionneront lorsqu'ils seront utilisés. Et vous pouvez configurer l'état & amp; invoquez facilement les méthodes déléguées pour les tester.

De plus, vous ne disposez pas de la visibilité des méthodes public / protégé / privé, ce qui empêche de rédiger des tests pour vos internes.

Règle d'or: Si vous allouez , vous relâchez !

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 à 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. AbstractFooFactory et FooFactory et IFoo et Foo volaient beaucoup alors que tout ce dont ils avaient vraiment besoin était une classe Foo et éventuellement un protocole Fooable.

Pour vous en assurer, il est essentiel de 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 Déboguer Magic . Ce 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, puis provoquer des plantages (comme lors de l'arrêt de l'application).

Triez les chaînes à la demande de l'utilisateur

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 d'informations, voir Recherche, comparaison et tri 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, en ajoutant de petites catégories utiles à toutes les classes existantes ( "Quoi? Je peux ajouter une méthode pour convertir un nombre en chiffres romains en NSNumber"! ).

Ne faites 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 ne réutilisez jamais la méthode.

Il y a aussi d'autres dangers, à moins que vous fassiez un namespace à vos méthodes de catégorie (et qui en plus de la ddribin complètement folle, est?) la même méthode de catégorie avec le même nom avec un effet secondaire légèrement différent ....

OK Maintenant que vous avez été averti, ignorez l'option "Ne faites pas cette partie". Mais faites preuve d'une extrême retenue.

Résistez à la sous-classification du monde. Dans Cocoa, la délégation et l’utilisation du moteur d’exécution sous-jacent sont très répandus. Dans d’autres frameworks, le sous-classement est utilisé.

Par exemple, en Java, vous utilisez beaucoup les instances de * Listener anonymes et, en .NET, vous utilisez souvent les sous-classes EventArgs . Dans Cocoa, vous ne le faites pas non plus - l’action cible est utilisée à la place.

Propriétés déclarées

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 avant de ne pas marquer les propriétés comme "non atomiques". En tant que le guide du langage de programmation Objective C , ses propriétés sont atomique par défaut, et encourir 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 '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.

Pensez aux valeurs nulles

En tant que cette question , des notes à nil sont valables en 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 êtes '. Je ne m'y attendais 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 spécification:

  

En général, les méthodes dans différents   classes qui ont le même sélecteur   (le même nom) doit également partager le   mêmes types de retour et d'argument. Ce   la contrainte est imposée par le compilateur   autoriser la liaison dynamique.

Dans ce cas, tous les mêmes sélecteurs nommés, même si ils se trouvent dans des classes différentes , seront considérés comme ayant des types de renvoi / 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 > Commencez avec l'outil de performance > 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 Afficher > Détail (il devrait y avoir une coche). Sous " Allocation Lifespan " dans le détail ObjectAlloc, assurez-vous de choisir le bouton radio en regard de "Créé & amp; Nature morte ".

Maintenant, chaque fois que vous arrêtez d'enregistrer votre application, sélectionnez l'outil ObjectAlloc pour afficher le nombre de références à chaque objet encore vivant de votre application dans l'onglet "# Net". colonne. 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 pas de 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 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 de l'objet 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];
}

Ceci 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éderait à nouveau à la variable membre - rare mais pourrait se produire. ).

Avec GC activé dans la version 10.5, cela n’est plus tellement nécessaire - vous pouvez quand même avoir besoin de nettoyer les autres ressources que vous créez, vous pouvez le faire avec la méthode de finalisation à la place.

Tous ces commentaires sont excellents, mais je suis vraiment surpris que personne n'ait mentionné de Google Objective-C Style Guide publié il y a longtemps. 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 conseils Xcode & amp; trucs que vous souhaiteriez connaître il y a 2 ans? .

N'oubliez pas que NSWindowController et NSViewController publieront 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 dernière lorsque vous en avez terminé.

L'une des plus évidentes 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 que vous avez collé le code, 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.

Xcode va réellement analyser cette section et la mettre en retrait sur la base 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.

Je sais que j'ai négligé cela lors de ma première entrée dans 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.

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 fréquemment l'analyse statique de Clang; vous pouvez l'activer pour toutes les versions via l'option & Run; Exécuter Static Analyzer " paramètre de construction.

Rédigez des tests unitaires et exécutez-les à chaque génération.

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 de 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 récupérerez les erreurs causées par l’oubli de & soi; soi-même. " 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 / N'utilisez jamais de retenue ou de libération directement sur les propriétés (ou uniquement 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 rétention / libération par elles-mêmes. Vous ne savez jamais si un passeur n'est pas, par exemple, ajouter ou supprimer des observateurs. Vous ne devez utiliser la variable directement qu’à l’intérieur de ses fonctions de définition et d’obtention.

Vues

1 / Si vous le pouvez, placez chaque définition de vue dans un fichier xib (à l'exception des paramètres de contenu dynamique et de calque). Cela fait gagner du temps (c'est plus facile que d'écrire du code), il est facile de le changer et ça 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 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 à partir de votre méthode dealloc. Il n'est pas appelé implicitement.

Mémoire

1 / Libération automatique des objets lorsque vous les créez. 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 avec 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 retenue 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 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 de POO 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 identique à:


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 régulièrement. Essayez d'apprendre de vos insectes. Comprenez pourquoi un bogue a été créé et essayez de l’éviter en utilisant les normes de codage.

Nos normes de codage ont actuellement une vingtaine de pages, un mélange de normes de codage Java, de normes Google Obj-C / C ++ et de nos propres ajouts. Documentez votre code, utilisez l'indentation standard, les espaces et les lignes vierges aux bons endroits, etc.

.

Soyez plus fonctionnel .

Objective-C est un langage orienté objet, mais le style fonctionnel du framework Cocoa est conçu et est conçu dans de nombreux cas.

  1. Il y a séparation de la mutabilité. Utilisez les classes immuable en tant qu'objet primaire et les objets mutables en tant qu'objets secondaires. Par exemple, utilisez principalement NSArray et NSMutableArray uniquement lorsque vous en avez besoin.

  2. Il y a des fonctions pures. Pas si nombreux, achetez beaucoup d'API du framework sont conçues comme des fonctions pures. Examinez 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.

  1. Il y a une évaluation paresseuse. Voir quelque chose comme propriété - [vue UIViewController] . 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 chargé qu'une fois 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.

  2. Il y a fermeture. Utilisez autant que possible les blocs en C. Cela simplifiera grandement votre vie. Mais lisez à nouveau sur la gestion de la mémoire de blocs avant de l’utiliser.

  3. Il existe un CPG 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)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top