7
votes

Initialisation des variables d'instance dans le développement de l'iPhone / objectif-c

Ê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> xxx pré>

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

b) paramètre em> p> xxx pré>

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> xxx pré>

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>

- (void) viewDidLoad // or - (void) loadView if you implemented your view programmatically
{
    [super viewDidLoad];

    [self setInstanceVariable: [InstanceVariableClass instanceVariableClassWithInt:1]];
}


0 commentaires

4 Réponses :


2
votes

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 @property et @synthesize ) sauf s'il est nécessaire d'éviter un goulot d'étranglement de la performance.

Alors, mes constructeurs normalement Regardez quelque chose comme ceci: xxx

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.


0 commentaires

0
votes

Premier, l'objectif-c n'a pas de variables de classe; juste des variables d'instance.

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 -Init * 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 * et -DeAlloc , alors vous avez probablement des problèmes d'architecture de bien pires en jeu. < / p>

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

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

  3. AutoRelease n'est rien d'autre qu'un libération de code . Bien que, généralement, vous n'avez pas besoin de vous inquiéter des objets AutoRelease 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.

    Ceci est tout expliqué en détail dans le Gestion de la mémoire Objective-C Guide .

    pense à cela de cette façon:

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

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


4 commentaires

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 se produit sur la mission de propriété devrait être hors de propos de votre périmètre d'appel.



0
votes

Senario 1 a)
C'est un code inutile. Nsarray est immuable, donc une fois créé, il ne peut pas être changé. Donc, plutôt ce instanceArray = nil; ou un événement mieux do auto.instanaRray = nil;

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.

1b) Si votre propriété est définie sur (Conserver), utilisez-la instaurée Self.InstanceArray = paramètrearray

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.
Et le code de votre montrant là-bas, eh bien je suis sûr que ce n'est pas compilé.

Senario 2a)
Même réponse que 1a)

même réponse que 1C)

autant que possible, utilisez votre propriété . Donc, si vous avez une variable qui soit maintenue en synchronisation, il est plus facile de faire de cette façon.
Et assurez-vous de comprendre la différence entre Nsarray et NsmutableArray. (ou toute autre classe ayant une version mutable et immuable)


Quant à la différence entre un UIViewController et un non-UIViewController.
(Ok ils peuvent, mais ils sont nil à ce point)

Iboutlet ne peut pas être consulté dans la méthode init. Donc, ils doivent en initialiser plus tard.

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

Ce sont des lignes de guidage et comme toutes les lignes de guidage, vous devez parfois plier la ligne un peu.


2 commentaires

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.



3
votes

1a) pefect, mis à part en ce bit:

Appeler conserver sur lui-même automatiquement

instanceArray ne conserve pas elle-même - il s'agit simplement d'une affectation à la mémoire brute réservée à votre instance.

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.

1b) C'est extrêmement rare (pour moi) de déclarer une propriété nsarray comme Conserver - Vous devez utiliser copier . 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]; .

1c) semble bon, mais vous devez également considérer les points que j'ai faits à 1A et 1b.

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.


4 commentaires

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