Être assez nouveau sur le développement iPhone / Objective-C, je voulais poser cette question à s'assurer que je vais à l'initialisation des variables d'instance correctement dans différents scénarios. Donc, ci-dessous, je vais présenter quelques scénarios et si quelqu'un voit tout ce qui est mal fait, peut-il s'il vous plaît laissez-moi savoir. (Remarque: pour mes exemples, j'utiliserai "instancevariable" pour la variable d'instance que nous cherchons à initialiser, ce qui est un objet de classe "instancevariableclass".)
scénario 1: Initialisation dans un non-UIViewController Classe forte> p> a) nouvelle allocation em> p> dans l'initialiszer, il est correct d'accéder à la variable directement ( c'est-à-dire pas à travers sa propriété) et l'allouer. Lorsque vous appelez Alloc, l'objet nouvellement créé sera automatiquement conservé, ce qui fonctionnera parfaitement plus tard lorsque vous l'utilisez avec vos méthodes Getter et Setter. Vous ne voulez pas allouer la variable à l'aide d'une propriété, c'est-à-dire b) paramètre em> p> encore une fois, OK pour accéder directement à votre variable d'instance dans le Initializer. Puisque vous n'acceptez pas la variable et que vous souhaitez simplement posséder une copie qui vous a été transmise, vous devez l'avoir explicitement conserver. Si vous aviez utilisé votre méthode de setter, cela vous aurait conservé pour vous, mais souhaitez éviter d'accéder aux propriétés de l'initialiseur. p> c) méthode de commodité em> p> Lorsque vous utilisez une méthode de commodité pour renvoyer un nouvel objet, vous devez également conserver explicitement pour les mêmes raisons qu'un paramètre. La méthode de la commodité (si elle est implémentée correctement) aura automatiquement modifié le nouvel objet qu'il génère. Nous n'avons donc pas à vous soucier de le retenir. P> Scénario 2: Initialisation d'une classe UIViewController forte> p> a) nouvelle allocation em> p> self.instancevariable = [[[[[[[instancevariableclass Alloc] init]; Code> Ou bien, vous le ferez deux fois (une fois dans votre méthode de réglage et un avec l'alloc). p>
- (void) viewDidLoad // or - (void) loadView if you implemented your view programmatically
{
[super viewDidLoad];
[self setInstanceVariable: [InstanceVariableClass instanceVariableClassWithInt:1]];
}
4 Réponses :
Tous les exemples que vous avez fournis sont parfaitement valides.
Cependant, de nombreux programmeurs OBJ-C expérimentés préfèrent les variables d'instance d'accès jamais, à l'exception de leurs méthodes de jeu / get (qui ne peuvent pas existent même si vous les déclarez avec Alors, mes constructeurs normalement Regardez quelque chose comme ceci: p> mais je choisirai parfois d'écrire mon code exactement comme vous l'avez fait, si le code indique les méthodes SET / GET et les pools de l'Autoreleas sont en train de prendre. trop de temps processeur ou de bélier. p> p> @property code> et
@synthesize code>) sauf s'il est nécessaire d'éviter un goulot d'étranglement de la performance. P>
Premier, l'objectif-c n'a pas de variables de classe; juste des variables d'instance. P>
Deuxièmement, vous pensez bien cela. Les règles de gestion de la mémoire sont relativement simples et orthogonales à des méthodes de réglage / getter et / ou de création d'objets. L'utilisation du setter dans un Si vous + NOUVEAU, + ALLOC, -Retain ou -Copy [NARC] [NARC] Un objet, vous devez-le -relez-le quelque part ou cela va rester autour (et, probable, fuite). P > li>
Si un séchit veut garder une prise d'un objet, il ne le fera pas ou le dépouiller (le cas échéant) et c'est que c'est une entreprise d'équilibrer le -retain. Extérieurement au setter vous ne devriez pas vous engager em>. P> li>
Ceci est tout expliqué en détail dans le Gestion de la mémoire Objective-C Guide . P>
pense à cela de cette façon: p>
Lorsque vous effectuez une mission directe à un ivar, vous ne quittez pas la portée de l'appel et, par conséquent, l'affectation peut consommer le nombre de retenue +1 conservé (éventuellement) dans la portée d'appel. P> li>
Lorsque vous attribuez à travers un appel de méthode (syntaxe de point ou autrement), le nombre de retenue étant maintenu dans votre péril d'appel n'est pas pertinent de ce qui se passe dans cette méthode de réglage. Les deux sont tenus de maintenir leurs deltas de retenue respectifs de manière indépendante. C'est-à-dire que si le setter veut garder l'objet autour, cela le conservera. L'appelant maintient qu'il conserve le nombre de comptes indépendamment. P> li>
ul> -Init * code> est un problème dans lequel vous pouvez déclencher des effets secondaires si le setter est remplacé. Toutefois, si vous avez des effets secondaires de réglage / getter dans la lecture de la lecture pendant
-Init * code> et
-DeAlloc code>, alors vous avez probablement des problèmes d'architecture de bien pires en jeu. < / p>
AutoRelease code> n'est rien d'autre qu'un libération de code code> code>. Bien que, généralement, vous n'avez pas besoin de vous inquiéter des objets code> AutoRelease de code> d Créé via les différentes méthodes de création d'instance d'objet de commodité, la pression automatique peut être un problème de performance réel dans certaines circonstances et à l'aide d'un Alloc Explicit + Alloc / Set / -Release peut être utile. p> li>
ol>
Vous pouvez avoir une variable statique qui sont des variables de classe. Pensez simplement à un singleton.
Merci pour ça. Oui, je comprends tous ces principes, mais je consultitais un sous-ensemble spécifique, c'est-à-dire lorsque vous initialisez des variables qui possèdent des cas particuliers que vous ne voyez normalement pas, c'est-à-dire si vous accédez directement à la variable dans l'initialisateur ou l'utilisation de la propriété, ou comment s'initialiser dans une brise de vue.
Vinceburn: une variable statique est accessible à l'ensemble du champ d'application de la déclaration et peut couvrir plusieurs classes (si plusieurs @Implementations existent dans une seule unité de compilation).
@Codefro Mon point était que vos "cas spéciaux" n'existent que parce que vous êtes en train de colluer des concepts qui sont autrement orthogonaux. Si vous suivez la règle NARC, rien d'autre ne compte. Qu'un conserve code> se produit sur la mission de propriété devrait être hors de propos de votre périmètre d'appel.
Senario 1 a) 1b) Si votre propriété est définie sur (Conserver), utilisez-la instaurée 1c) Ce n'est pas une méthode de commodité. La méthode de commodité est généralement une méthode de classe qui renvoie l'objet AutoRelease. Senario 2a) même réponse que 1C) p>
Quant à la différence entre un UIViewController et un non-UIViewController. Iboutlet ne peut pas être consulté dans la méthode init. Donc, ils doivent en initialiser plus tard. p>
Ainsi, de manière générale, le côté des données doit être effectué dans l'init, la consultation de la costomisation dans le code devrait entrer dans la vueDiDload, et la logique lente et / ou rafraîchir devraient entrer dans la viewwillappear. Ce sont des lignes de guidage et comme toutes les lignes de guidage, vous devez parfois plier la ligne un peu. P>
C'est un code inutile. Nsarray est immuable, donc une fois créé, il ne peut pas être changé. Donc, plutôt ce instanceArray = nil; code> ou un événement mieux do
auto.instanaRray = nil; code>
Si InstanceArray était un nsmutableArray, il serait logique de l'attribuer là-bas, mais comme ce n'est pas le cas, c'est un gaspillage. P>
Self.InstanceArray = paramètrearray code> p> p>
Et le code de votre montrant là-bas, eh bien je suis sûr que ce n'est pas compilé. P>
Même réponse que 1a) p>
Et assurez-vous de comprendre la différence entre Nsarray et NsmutableArray. (ou toute autre classe ayant une version mutable et immuable) p>
(Ok ils peuvent, mais ils sont nil code> à ce point) p>
N'oubliez pas que la viewwillappear sera appelée à chaque fois que la vue est sur le point d'apparaître, y compris lorsque vous revenez de plus bas dans la hiérarchie UIViewController. p>
Ok j'ai corrigé la chose nsmutableArray, bien que c'était vraiment en plus du point de mon exemple. Oui, je sais que vous devriez utiliser une propriété, mais certaines personnes disent que vous ne devriez pas l'utiliser dans une initiative.
Je ne vois pas pourquoi, la seule exception que je puisse penser serait dans une méthode initwithcoder tout en mettant en œuvre un protocole NSCODING et qu'il pourrait toujours être discutable. La méthode Accessor existe donc vous pouvez avoir un point d'accès unique à votre variable. Cela vous aide à avoir un code plus durable.
1a) pefect, mis à part en ce bit: p>
Appeler conserver sur lui-même automatiquement p> blockQuote>
instanceArray code> ne conserve pas elle-même - il s'agit simplement d'une affectation à la mémoire brute réservée à votre instance. P>
Une partie critique que vous avez bien obtenue, que beaucoup de gens négligent, c'est que vous devriez Évitez d'utiliser les accesseurs dans les états partiellement construits / destructs . La raison n'est pas que le comptage de référence, c'est également un flux de programme approprié dans ces états. P>
1b) C'est extrêmement rare (pour moi) de déclarer une propriété
nsarray code> comme
Conserver code> - Vous devez utiliser
copier code>. Votre initialiseur doit être d'accord avec la sémantique de votre propriété , donc dans la plupart des Cas, vous changeriez cela en
InstanceArray = [Copie ParamenerAry]; Code>. P>
1c) semble bon, mais vous devez également considérer les points que j'ai faits à 1A et 1b. p>
2) Eh bien, cela dépend vraiment. L'initialisation paresseuse n'est pas toujours la meilleure. Il y a des cas où il sera préférable d'initialiser vos ivars dans l'initialisateur, et certains lorsque la vue est chargée. N'oubliez pas que votre VC peut être déchargé et qu'il est assez typique de détruire ce que vous créez lors du chargement. Ainsi, il n'y a donc vraiment pas une règle dure et rapide - si quelque chose prend le temps de créer ou de la persister dans l'événement que votre VC est rechargé, il peut être plus logique de gérer cela dans l'initialisateur. Les exemples ont l'air bien, lorsque l'initialisation paresseuse est préférable. P>
Je viens de me débarrasser des matrices parce que c'était en plus du point et mettait dans une variable "instance votée" de la classe "instancevariableclass". En outre, remplaçait la ligne que vous parliez avec "lorsque vous appelez Alloc, l'objet nouvellement créé sera automatiquement conservé". Est-ce que ça fait plus de sens?
@CODEFRO OK. C'est un peu plus correct de dire (quelque chose dans le sens de): "Lorsque vous êtes retourné un objet de son initialiseur, vous êtes responsable de la relâcher lorsque vous avez fini avec cela. L'instance que nous avons créée et stockée sur cet ivar sera envoyée. Sa version correspondante lorsque le Setter est appelé ou dans DealLoc code> ".
ALLOC CODE> d'une instance doit être associé à son initialisateur.
Il convient de mentionner que le point 1a de votre réponse est un sujet appliqué vivement. Il y a beaucoup de désaccord sur la question de savoir si des méthodes d'accessoir de propriété doivent être utilisées dans Init / DealLoc. Mon opinion personnelle est l'exactement opposé de ce que vous recommandez - les variables doivent toujours être accessibles par leur propriété, même à l'intérieur init / Dealloc, et un objet doit comprendre suffisamment de lui-même pour le faire de manière sûre.
@Abhi Je sais qu'il y a des gens avec cette préférence, mais la préférence ne devrait pas dépasser l'exactitude du programme, la maintenabilité, la bonne conception ou la maintien dans le domaine du comportement défini. Peut-être que vous allez changer d'avis après que cela vous a assez troublé (comme je l'ai fait il y a des années).