Quelles sont les meilleures pratiques que vous utilisez lors de l'écriture d'Objective-C et de Cocoa? [fermé]


346

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).


voir cet article de blog, très sympa. ironwolf.dangerousgames.com/blog/archives/913
user392412

Réponses:


398

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 someFloatpeut 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 atomicpar 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


3
Bon conseil sur la double arithmétique.
Adam Ernst

8
Les extensions de classe sont désormais le moyen préféré pour les méthodes privées: developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/…
Casebash

9
Vos conseils sur les doublons sur iPhone sont obsolètes stackoverflow.com/questions/1622729/…
Casebash

3
Pas obsolète; tout à fait faux: l'iPhone original pris en charge flotte et double dans le matériel à environ la même vitesse. SQLite ne conserve pas non plus les transactions en mémoire; ils sont journalisés sur disque. Seules les longues requêtes bloquent votre interface utilisateur; il est moins compliqué d'exécuter tout dans le thread principal et d'utiliser des requêtes plus rapides.
tc.

1
@tc: J'ai corrigé l'élément SQL sur les transactions, notez que je n'ai pas écrit moi-même ces quatre derniers éléments. J'ai également clarifié la partie concernant le déplacement des requêtes en arrière-plan uniquement pour les requêtes très longues (parfois vous ne pouvez pas les raccourcir). Mais qualifier le tout de «mauvais» à cause de quelques points, je me sens plutôt extrême. En outre, la réponse ci-dessus a déjà déclaré: "Sur les téléphones plus anciens, les calculs fonctionnent à la même vitesse", mais notez la partie concernant le plus grand nombre de registres à simple précision, ce qui les rend encore préférables.
Kendall Helmstetter Gelner

109

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

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);

4
J'ai déjà été mordu par celui-ci.
Adam Ernst

C'est un bon conseil pour n'importe quel langage de programmation
Tom Fobear

107

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:

  • Ne déclarez pas id m_something;dans l'interface d'un objet et appelez-le une variable ou un champ membre ; utiliser somethingou _somethingpour son nom et l'appeler un variable d'instance .
  • Ne nommez pas un getter -getSomething ; le nom Cocoa correct est juste -something.
  • Ne nommez pas un setter -something: ; ça devrait être-setSomething:
  • Le nom de la méthode est intercalé avec les arguments et inclut les deux-points; ses-[NSObject performSelector:withObject:] pas le cas NSObject::performSelector.
  • Utilisez des majuscules (CamelCase) dans les noms de méthode, les paramètres, les variables, les noms de classe, etc. plutôt que les barres de soulignement (traits de soulignement).
  • Les noms de classe commencent par une lettre majuscule, les noms de variable et de méthode par une minuscule.

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.


5
Je dirais, n'utilisez pas setSomething: / quelque chose du tout - utilisez plutôt des propriétés. À ce stade, il y a peu de gens qui ont vraiment besoin de cibler Tiger (la seule raison de ne pas utiliser de propriétés)
Kendall Helmstetter Gelner

18
Les propriétés génèrent toujours des méthodes d'accesseur pour vous, et les attributs getter = / setter = de la propriété vous permettent de spécifier les noms des méthodes. De plus, vous pouvez utiliser la syntaxe [foo something] au lieu de la syntaxe foo.something avec des propriétés. La dénomination des accesseurs est donc toujours pertinente.
Chris Hanson

3
C'est une excellente référence pour quelqu'un qui vient de C ++, où j'ai fait la plupart des choses contre lesquelles vous déconseillez.
Clinton Blackmore

4
Un setter ne doit pas provoquer l'enregistrement de quelque chose dans la base de données. Il y a une raison pour laquelle Core Data a une méthode -save: sur NSManagedObjectContext, plutôt que de demander aux setters de générer des mises à jour immédiates.
Chris Hanson

2
Je doute que ce ne soit pas une option, mais cela a peut-être nécessité de revoir l'architecture de votre application. (Pour être clair: je ne dis pas "Vous auriez dû utiliser Core Data." Je dis "Les setters ne devraient pas enregistrer dans la base de données.") Avoir un contexte pour gérer un graphique d'objet, plutôt que d'enregistrer des objets individuels dedans , est pratiquement toujours à la fois possible et une meilleure solution.
Chris Hanson

106

IBOutlets

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.


1
le chargement de la plume ne le retiendrait-il pas deux fois? (une fois dans la plume, deuxième par affectation à la propriété). Suis-je censé les libérer en dealloc?
Kornel

6
Vous devez mettre à zéro les prises dans viewDidUnload (iPhone OS 3.0+) ou dans une méthode setView: personnalisée pour éviter les fuites. Évidemment, vous devriez également publier dans dealloc.
Frank Szczerba

2
Gardez à l'esprit que tout le monde n'est pas d'accord avec ce style: weblog.bignerdranch.com/?p=95
Michael

C'est aussi la façon dont Apple fait les choses. "Début du développement de l'iPhone 3" mentionne également ce changement par rapport aux versions précédentes.
ustun

Je l'ai mentionné dans un autre commentaire, mais j'aurais dû le placer ici: Une fois que la synthèse dynamique d'ivar commence à se produire pour les applications iOS (si / quand?), Vous serez heureux d'avoir mis IBOutlet sur la propriété par rapport à l'ivar!
Joe D'Andrea

97

Utilisez l'analyseur statique LLVM / Clang

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:

  1. Téléchargez la dernière version depuis cette page .
  2. De la ligne de commande, cdvers votre répertoire de projet.
  3. Exécutez 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.


1
J'ai eu du mal à le faire fonctionner jusqu'à ce que je suive ces instructions: oiledmachine.com/posts/2009/01/06/…
bbrown

15
Dans XCode 3.2.1 sur Snow Leopard, il est déjà intégré. Vous pouvez soit l'exécuter manuellement, en utilisant Exécuter -> Générer et analyser , soit l'activer pour toutes les générations via le paramètre de génération «Exécuter l'analyseur statique». Notez que cet outil ne prend actuellement en charge que C et Objective-C, mais pas C ++ / Objective-C ++.
OEFE

94

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 deallocdisparaî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;

8
Il n'y a rien de subtil à cela, la documentation indique clairement que vous devez le faire. De 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.
johne

Il vaut mieux utiliser nil au lieu de NULL, car NULL ne libérera pas la mémoire.
Naveen Shan

@NaveenShan nil == NULL. Ils sont exactement les mêmes sauf que nilc'est un idet NULLest un void *. Votre déclaration n'est pas vraie.

@WTP yep, nil == NULL, mais utiliser nil est clairement le moyen préféré, si vous regardez des exemples de fragments de code de pommes, ils utilisent nil partout, et comme vous l'avez dit, nil est un identifiant, ce qui le rend préférable au vide * , dans les cas où vous envoyez des identifiants, c'est-à-dire.
Ahti

1
@Ahti exactement, et Nil(majuscule) est de type Class*. Même s'ils sont tous égaux, utiliser le mauvais peut introduire de petits bugs désagréables, en particulier dans Objective-C ++.

86

@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.


Vous pouvez le faire, mais j'aime l'étiqueter explicitement comme une section "privée" (plus de documentation que fonctionnelle), bien sûr, cela est déjà assez évident du fait qu'il se trouve dans le fichier .m ...
Kendall Helmstetter Gelner

2
Sauf qu'il existe une différence entre les catégories privées et les extensions de classe: "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, comme illustré dans l'exemple suivant:" Voir le lien en cours d'édition.
schwa

Je suis d'accord qu'il y a une différence où le compilateur vous avertira lorsque vous n'avez pas implémenté les méthodes CE - mais je ne trouve pas cet aspect très important lorsque toutes les méthodes sont dans le même fichier et toutes privées. Je préfère toujours l'aspect maintenabilité du marquage du bloc de référence avant comme privé
Kendall Helmstetter Gelner

3
Je ne pense vraiment pas que (Private) soit plus facile à maintenir que (). Si vous êtes si inquiet, une bonne dose de commentaires pourrait vous aider. Mais visiblement vivre et laisser vivre. YMMV etc.
schwa

17
Il y a un avantage assez important à utiliser à la ()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. :)
Pascal

75

Évitez la libération automatique

É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 newObjectmé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 .


6
Je trouve que les avantages de ne pas utiliser la libération automatique l'emportent sur ses coûts (c.-à-d. Plus de bugs de fuite de mémoire). Le code sur le thread principal devrait de toute façon être assez court (ou sinon vous gèlerez l'interface utilisateur) et pour un code d'arrière-plan plus gourmand en mémoire, vous pouvez toujours envelopper les portions gourmandes en mémoire dans des pools de libération automatique locaux.
adib

56
Je ne suis pas d'accord. Vous devez utiliser des objets libérés automatiquement autant que possible. S'ils augmentent trop l'empreinte mémoire, vous devez en utiliser un autre NSAutoreleasePool. Mais seulement après avoir confirmé que c'est vraiment un problème. Optimisation prématurée et tout ça ...
Sven

3
Je passe moins de 40 sec. un jour en tapant [version someObject] et en lisant la "ligne supplémentaire" lors de l'instanciation d'un nouvel objet, mais j'ai une fois brûlé pendant 17 heures pour trouver un bug de libération automatique qui n'apparaîtrait que dans des cas spéciaux et ne donnerait aucune erreur cohérente dans la console. Je suis donc d'accord avec adib quand il dit: "Je trouve que les avantages de ne pas utiliser la libération automatique l'emportent sur ses coûts".
RickiG

7
Je suis d'accord avec Sven. L'objectif principal doit être la clarté du code et la réduction des erreurs de codage, avec une optimisation de la mémoire uniquement là où elle est nécessaire. Taper un [[[Foo alloc] init] autorelease] est rapide et vous traitez immédiatement le problème de la libération de ce nouvel objet. Lors de la lecture du code, vous n'avez pas à chercher la version correspondante pour vous assurer qu'elle ne fuit pas.
Mike Weller

3
Le cycle de vie des objets libérés automatiquement est bien défini et déterminable à un niveau suffisant.
Eonil

69

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

  • Suivez les règles de dénomination KVO.Même si vous n'utilisez pas KVO maintenant, selon mon expérience, il est souvent bénéfique à l'avenir. Et si vous utilisez KVO ou des fixations, vous devez savoir que les choses fonctionnent comme elles le devraient. Cela couvre non seulement les méthodes d'accesseur et les variables d'instance, mais les relations à plusieurs, la validation, les clés dépendantes à notification automatique, etc.
  • Mettez les méthodes privées dans une catégorie. Pas seulement l'interface, mais aussi l'implémentation. Il est bon d'avoir une certaine distance conceptuelle entre les méthodes privées et non privées. J'inclus tout dans mon fichier .m.
  • Mettez les méthodes de thread d'arrière-plan dans une catégorie.Comme ci-dessus. J'ai trouvé qu'il est bon de garder une barrière conceptuelle claire lorsque vous pensez à ce qui est sur le fil principal et ce qui ne l'est pas.
  • Utilisez #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ù.
  • Préfixez les méthodes privées et les ivars avec _.J'aime son apparence et je suis moins susceptible d'utiliser un ivar lorsque je parle d'une propriété par accident.
  • N'utilisez pas de méthodes / propriétés de mutateur dans init & dealloc.Je n'ai jamais rien fait de mal à cause de cela, mais je peux voir la logique si vous changez la méthode pour faire quelque chose qui dépend de l'état de votre objet.
  • Mettez IBOutlets dans les propriétés. En fait, je viens de lire celui-ci ici, mais je vais commencer à le faire. Quels que soient les avantages de la mémoire, cela semble mieux sur le plan stylistique (du moins pour moi).
  • Évitez d'écrire du code dont vous n'avez pas absolument besoin. Cela couvre vraiment beaucoup de choses, comme faire des ivars quand #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.
  • Terminez ce que vous commencez. Ayant beaucoup de code à moitié fini, le buggy est le moyen le plus rapide de tuer un projet mort. Si vous avez besoin d'une méthode de stub qui convient, indiquez-la simplement en la mettant à l' NSLog( @"stub" )intérieur, ou comme vous voulez garder une trace des choses.

3
Je suggère que vous mettiez des méthodes privées dans une continuation de classe. (ie @interface MyClass () ... @end in your .m)
Jason Medeiros

3
Au lieu de #PRAGMA, vous pouvez utiliser un commentaire // Mark: [Section] qui est plus portable et fonctionne de manière identique.
aleemb

Sauf s'il manque une syntaxe spéciale, // Mark: n'ajoute pas d'étiquette dans le menu déroulant des fonctions de Xcode, ce qui est en fait la moitié de la raison de son utilisation.
Marc Charbonneau

6
Vous devez utiliser des majuscules, "// MARK: ...", pour qu'il apparaisse dans la liste déroulante.
Rhult

3
En ce qui concerne Finish what you startvous pouvez également utiliser // TODO:pour marquer le code pour l'achèvement qui apparaîtra dans la liste déroulante.
iwasrobbed

56

É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.


Quels cadres de test recommandez-vous?
melfar

13
Xcode inclut OCUnit, un framework de tests unitaires Objective-C et la prise en charge de l'exécution de lots de tests unitaires dans le cadre de votre processus de génération.
Chris Hanson

55

Règle d'or: Si vous allocalors vous release!

MISE À JOUR: sauf si vous utilisez ARC


26
Aussi , si vous copy, mutableCopy, newou retain.
Sven

54

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.


10
En tant que développeur Java qui a écrit une usine abstraite dans Objective-C, je trouve cela intrigant. Pourriez-vous expliquer un peu plus comment cela fonctionne - peut-être avec un exemple?
teabot

2
Croyez-vous toujours que nous n'avons pas besoin de classes d'usine abstraites après tout le temps écoulé depuis que vous avez posté cette réponse?
kirk.burleson

50

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).


1
Il existe maintenant une version spécifique à iOS de la page Debugging Magic .
Jeethu

38

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.


J'aime votre réponse, mon conseil ne devrait pas utiliser une catégorie pour stocker le code utilitaire à moins que vous ne soyez sur le point de répliquer du code dans plus d'un endroit et que le code appartient clairement à la classe que vous êtes sur le point de catégoriser ...
Kendall Helmstetter Gelner

Je voudrais simplement apporter ma voix et exprimer mon soutien aux méthodes de catégorie d'espaces de noms. Cela semble être la bonne chose à faire.
Michael Buckley

+1 si seulement pour les chiffres romains. Je ferais totalement ça!
Brian Postow

14
Contrepoint: Depuis un an et demi, j'ai suivi exactement la politique opposée: "Si cela peut être implémenté dans une catégorie, faites-le." Par conséquent, mon code est beaucoup plus concis, plus expressif et plus facile à lire que l'exemple de code détaillé fourni par Apple. J'ai perdu un total d'environ 10 minutes à cause d'un conflit d'espace de noms, et j'ai probablement gagné des mois-hommes grâce aux gains d'efficacité que je me suis créés. À chacun, mais j'ai adopté cette politique en connaissant les risques, et je suis extrêmement content de l'avoir fait.
cduhn

7
Je ne suis pas d'accord. Si cela va être une fonction et qu'elle s'applique à un objet Foundation, et que vous pouvez penser à un bon nom, collez-le dans une catégorie. Votre code sera plus lisible. Je pense que le point saillant ici est: faites tout avec modération.
mxcl

37

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 *Listenersous-classes anonymes et en .NET, vous utilisez EventArgsbeaucoup vos sous-classes. Dans Cocoa, vous ne faites pas non plus - l'action cible est utilisée à la place.


6
Autrement appelé "Composition sur héritage".
Andrew Ebling

37

Trier les chaînes comme l'utilisateur le souhaite

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 .


31

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 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.


26

Pensez aux valeurs nulles

Comme le note cette question , les messages à nilsont 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 nilvaleur alors que vous ne vous y attendiez pas.


J'ai ceci: #define SXRelease(o); o = nilet la même chose pour CFReleaseet free. Cela simplifie tout.

26

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.



23

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

c'est facile à oublier. Important néanmoins
Brock Woolf

3
Ce n'est qu'une préoccupation lorsque vous vous abstenez de la frappe statique. Si le compilateur connaît le type, les types d'argument et de retour peuvent différer sans problème. Personnellement, je trouve que ce n'est pas souvent un problème. Apple a également beaucoup de méthodes qui portent le même nom mais diffèrent dans les types de retour. Enfin, il existe un indicateur de compilation pour vous avertir dans les cas ambigus.
Nikolai Ruhe

Si nous suivons les directives de la convention de dénomination d'Apple, cette situation ne se produira pas :)
Eonil

22

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.


21

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.


12
En général, vous ne devez pas utiliser de méthodes d'accesseur dans dealloc (ou init).
mmalc

1
En dehors des raisons de performances (les accesseurs sont légèrement plus lents que l'accès direct) pourquoi ne devrais-je pas utiliser les accesseurs dans dealloc ou init?
schwa

1
(a) Les raisons de performances sont parfaitement suffisantes en soi (surtout si vos accesseurs sont atomiques). (b) Vous devez éviter tout effet secondaire que les accesseurs peuvent avoir. Ce dernier est particulièrement un problème si votre classe peut être sous-classée.
mmalc

3
Je noterai que si vous utilisez le runtime moderne avec des ivars synthétisés, vous devez utiliser des accesseurs dans dealloc. Beaucoup de code d'exécution moderne est GC, mais pas tout.
Louis Gerbarg

1
Une vue plus étendue sur l'utilisation ou non des méthodes / propriétés des accesseurs dans -initet les -deallocméthodes peut être trouvée ici: mikeash.com/?page=pyblog/…
Johan Kool

17

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.


7
Hmm, le premier exemple est déjà plein de conneries. Ne documentez jamais les idiomes linguistiques. Si je trouvais ce genre de commentaires dans un fichier d'en-tête, je ne prendrais pas la peine de lire.
Stephan Eggermont

5
Oh mes yeux !!!!! Je ne peux pas croire ce que j'ai vu.
Eonil


13

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.


12

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.


Vous pouvez même définir Tab pour mettre en retrait puis faire Cmd-A et Tab.
Plumenator

10

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.


6
Ce n'est pas vrai. Que vous soyez ou non responsable de la publication d'objets de niveau supérieur dépend de la classe dont vous héritez et de la plateforme que vous utilisez. Voir developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/… entre autres.
mmalc

10

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.


Et, si vous le pouvez, activez «Traiter les avertissements comme des erreurs». Ne laisser aucun avertissement exister.
Peter Hosey

2
Un script pratique pour configurer votre projet avec les avertissements recommandés est disponible ici: rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
Johan Kool

10

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.


9

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.

  1. 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.

  2. 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 -copyau lieu de -retainlors 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.

  1. 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 viewde la première lecture de la propriété de l' appelant . UIImagene 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.

  2. 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.

  3. Il existe un GC semi-automatique. NSAutoreleasePool. Utilisez -autoreleaseprimaire. Utilisez le -retain/-releasesecondaire manuel lorsque vous en avez vraiment besoin. (ex: optimisation de la mémoire, suppression explicite des ressources)


2
Quant à 3), je proposerai l'approche inverse: utilisez la conservation / libération manuelle dans la mesure du possible! Qui sait comment ce code sera utilisé - et s'il est utilisé dans une boucle étroite, il peut faire exploser votre utilisation de la mémoire inutilement.
Eiko

@Eiko C'est juste une optimisation prématurée , ne peut pas être une orientation générale.
Eonil

1
Je pense que c'est plus une question de conception, surtout lorsque l'on travaille sur des classes de modèles. Je considère la croissance de la mémoire comme un effet secondaire, et ce n'est pas ce que je veux voir apparaître souvent. Pire, un autre développeur qui utilise mon code n'a d'autre chance que de regrouper des appels coûteux dans des pools de libération automatique (si possible - mes objets peuvent être envoyés vers un autre code de bibliothèque). Et ces problèmes sont difficiles à diagnostiquer plus tard, mais bon marché à éviter en premier lieu. Si vous copiez / libérez automatiquement des objets qui ont été transmis, vous risquez d'être perdu s'ils sont beaucoup plus gros que prévu. Je suis cependant plus détendu avec le code GUI.
Eiko

@Eiko J'accepte autoreleaseque la mémoire sera généralement conservée plus longtemps, et le manuel retain/releasepeut 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 :)
Eonil
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.