Gestion mémoire to-one relationShip

MickMick Membre
Bonjour à  tous,

c'est sûrement une question très nulle, mais j'avoue avoir un peu de mal avec ça :

J'ai un objet qui a une variable d'instance qui est un pointeur vers un autre objet (to-one relationship). Mon soucis est le suivant :
lorsque qu'un nouveau document est créé, cette relation n'est pas initialisée. selectedObject d'un popup est bindé sur cette relation : le popup indique alors "No Value", ce qui est bien.

Maintenant, si j'ouvre un fichier, dans la méthode initWithCoder, j'initialise via un [[decoder decodeObjectForKey:@clef] retain] => Le retain count est donc à  1... Mais alors, comment écrire l'accesseur ? Si j'écris un accesseur "classique" je doit releaser l'objet avant de l'écraser avec le nouveau que je retient. Mais si celui-ci n'est pas initialisé, (cas d'un nouveau fichier), je release "du vent" lors de l'accès au setter ? cela devrait crasher ? De même, dans le dealloc, je suis sensé releaser ou pas ? Dans le cas de l'ouverture, le retainCount est sensé être à  1, mais dans le cas d'un nouveau fichier, il est sensé être à  zéro ? Ou bien interface builder alloue un objet provisoire si la relation n'est pas allouée ?

Bref, si vous avez une explication ...
«1

Réponses

  • avril 2011 modifié #2
    Quand tu dis "je release du vent", tu parles de release une variable qui pointe sur nil. Or, tu peux faire ce que tu veux avec nil, ça ne fera strictement rien, et donc ça ne plantera pas. Ainsi, si maVariable = nil, alors [maVariable release] ne fera rien, et ne fera surtout pas planter l'application.

    Voilà  comment réécrire getter/setter pout ton objet "clef" (mais tout dépend de comment tu veux qu'il agisse.. retain.. copy.. assign. Vu ton code, ça sera du retain)
    <br />- (id)clef<br />{<br />	return [[clef retain] autorelease];<br />}<br /><br />- (void)setClef:(id)aClef<br />{<br />	if(clef!=aClef)<br />	{<br />		[self willChangeValueForKey:@&quot;clef&quot;]; // Si tu jamais tu utilises le KVO<br />		[clef release];<br />		clef = [aClef retain];<br />		[self didChangeValueForKey:@&quot;clef&quot;];<br />	}<br />	<br />}<br /><br />- (void)dealloc<br />{<br />	[clef release];<br />	[super dealloc];<br />}<br /><br />
    
  • cyranocyrano Membre
    14:41 modifié #3
    <br />- (id)clef<br />{<br />	return [[clef retain] autorelease];<br />}<br />
    


    j'ai bcq de mal avec ce code ;-)

    je peux encore le comprendre dans le cas d'une application multithreadée, encore faut t'il les NSLock ou @synchronized pour garantir le code.
  • MickMick Membre
    14:41 modifié #4
    Ok, mais alors quelles sont les bonnes règles de conception des classe de la couche données ? Pour l'instant je suis sur le schéma suivant:

    Pour toutes les propriétés "valeurs" qui ne sont pas des objets : on ne fait qu'une assignation simple dans le setter.
    Pour toutes les propriétés "valeurs" qui sont des objets (NSString, NSData, NSNumber, NSDate) : On vérifie que le nouvel objet n'est pas le même que l'ancien, on release l'ancien et on COPIE le nouveau
    Pour une to-one relationship : idem, mais en RETIENT le nouveau
    Pour une to-many : on initialise un NSMutableArray ou un NSMutableSet obligatoirement dans la méthode init .. mais comment déclarer la propriété ? Dans la doc, il est indiqué qu'il faut implémenter la méthode countOf<Key>, objectIn<Key>AtIndex:, ... Mais @synthetize fait-il cela ? faut-il donc se taper les accesseurs à  la main dans le cas des to-many relationships

  • CéroceCéroce Membre, Modérateur
    14:41 modifié #5
    dans 1304088790:

    Pour toutes les propriétés "valeurs" qui ne sont pas des objets : on ne fait qu'une assignation simple dans le setter.

    Oui.

    dans 1304088790:

    Pour toutes les propriétés "valeurs" qui sont des objets (NSString, NSData, NSNumber, NSDate) : On vérifie que le nouvel objet n'est pas le même que l'ancien, on release l'ancien et on COPIE le nouveau

    Non, on le copie pas (envoi d'un -[copy]), on le retient ( -[retain]). Ces objets n'étant pas modifiables, à  quoi bon créer une nouvelle instance en mémoire et copier ses attributs ?
    Ceci dit, en pratique, la méthode -copy de ces objets fait simplement un -[retain], donc leur envoyer -[retain] ou -[copy] revient au même.

    dans 1304088790:

    Pour une to-one relationship : idem, mais en RETIENT le nouveau

    Du coup, la règle n'est pas différente de ci-dessus.

    dans 1304088790:

    Pour une to-many : on initialise un NSMutableArray ou un NSMutableSet obligatoirement dans la méthode init .. mais comment déclarer la propriété ? Dans la doc, il est indiqué qu'il faut implémenter la méthode countOf<Key>, objectIn<Key>AtIndex:, ... Mais @synthetize fait-il cela ? faut-il donc se taper les accesseurs à  la main dans le cas des to-many relationships

    Tu confonds deux choses: l'accès à  la collection et l'accès à  son contenu.

    Par exemple, pour un NSMutableArray, si on déclare la propriété
    [tt]@property (retain) NSMutableArray *employees;[/tt]
    C'est l'accès à  la collection qu'on déclare.

    Comme tu le dis, en général, on l'alloue dans -init et on ne veut pas qu'un autre objet y touche, donc on va plutôt le déclarer ainsi:
    [tt]@property (readonly) NSMutableArray *employees;[/tt]
    Ainsi, seul le getter sera généré.

    Mais cette approche n'est pas très bonne, parce que les autres objets peuvent mettre le souk dans notre NSMutableArray: ajouter, supprimer des objets, les réordonner. On peut préférer ne pas exposer le NSMutableArray du tout, et obliger les autres objets à  toujours passer par notre classe.

    Dans ce cas, tu coderas les méthodes countOf<Key> et cie. Note qu'il ne s'agit pas de propriétés. Respecter les noms est important pour le Key-Value Coding (voir le guide).
  • 14:41 modifié #6
    dans 1304082527:

    <br />- (id)clef<br />{<br />	return [[clef retain] autorelease];<br />}<br />
    


    j'ai bcq de mal avec ce code ;-)

    je peux encore le comprendre dans le cas d'une application multithreadée, encore faut t'il les NSLock ou @synchronized pour garantir le code.


    NSLock, @synchronized, ou pas, c'est une habitude que j'ai pris et je ne vois pas en quoi elle serait mauvaise en tout cas.. Effectivement ça a son utilité dans une appli multi-threadée, mais je ne vois pas vraiment en quoi ça poserait problème de l'utiliser même dans un cas non multi-thread.
  • MickMick Membre
    14:41 modifié #7
    Donc, pour une to-many relationship, si j'ai bien compris, il ne faudrait carrément pas de getter qui retournerait le mutableArray, mais uniquement des méthodes d'ajout suppression et acces aux objets et au compte c'est ça ? (objectIn<Key>AtIndex ....)

    Quand utilise-t-on donc la copy/mutableCopy ? J'avais lu quelque part dans la doc qu'il fallait copier lorsqu'il s'agit d'attributs, et retenir quand il s'agit de relations...
  • zoczoc Membre
    14:41 modifié #8
    dans 1304082527:

    <br />- (id)clef<br />{<br />&nbsp;  return [[clef retain] autorelease];<br />}<br />
    


    j'ai bcq de mal avec ce code ;-)

    je peux encore le comprendre dans le cas d'une application multithreadée, encore faut t'il les NSLock ou @synchronized pour garantir le code.

    Non, même dans une application monothreadée ca a son intérêt... Petit exemple:


    <br />FooObject *foo = [[FooObject alloc] init];<br />....<br />id fooKey = [foo clef];<br /><br /><br />[foo release];<br />[fooKey bar];&nbsp; // &lt;-- Boom si methode clef pas écrite comme ci dessus.<br />
    
  • 14:41 modifié #9
    Ah oui très bon exemple Zoc! Je n'avais jamais songé à  ce cas d'usage ceci-dit.
  • CéroceCéroce Membre, Modérateur
    14:41 modifié #10
    dans 1304095279:

    Donc, pour une to-many relationship, si j'ai bien compris, il ne faudrait carrément pas de getter qui retournerait le mutableArray, mais uniquement des méthodes d'ajout suppression et acces aux objets et au compte c'est ça ? (objectIn<Key>AtIndex ....)

    Dans l'absolu, oui. Ce qu'on recherche dans la POO ce que chaque objet soit le plus indépendant possible des autres.
    Ceci dit, c'est quand même fastidieux et perso, à  moins d'utiliser le Key-Value Observing, je déclare la collection en propriété la plupart du temps.

    dans 1304095279:

    Quand utilise-t-on donc la copy/mutableCopy ? J'avais lu quelque part dans la doc qu'il fallait copier lorsqu'il s'agit d'attributs, et retenir quand il s'agit de relations...

    Il ne peut pas y avoir de règle stricte; ça dépend de l'architecture.
    En gros, quand on nous passe un objet mutable, si on veut être sûr qu'il ne va pas bouger il faut le copier.
    Pour les relations, pareil. Si on veut être sûr que rien ne bougera, il faut tout copier. Note que si tu copies un NSMutableArray, l'instance sera bien différente, mais pas contre les objets qu'il contient seront les mêmes. Il faudrait aussi copier tous les objets (en suivant leurs relations) pour s'assurer que rien ne bouge !

    C'est histoires de copie n'ont rien de simple. Essaie un jour de jouer avec l'Undo manager, tu vas voir, c'est plein de bonheur.
  • cyranocyrano Membre
    14:41 modifié #11
    FooObject *foo = [[FooObject alloc] init];<br />....<br />id fooKey = [foo clef];<br /><br /><br />[foo release];<br />[fooKey bar];&nbsp; // &lt;-- Boom si methode clef pas écrite comme ci dessus.
    


    tu es serieux la?

    ou juste pour donner un exemple ;-)
  • zoczoc Membre
    avril 2011 modifié #12
    dans 1304101658:

    FooObject *foo = [[FooObject alloc] init];<br />....<br />id fooKey = [foo clef];<br /><br /><br />[foo release];<br />[fooKey bar];&nbsp; // &lt;-- Boom si methode clef pas écrite comme ci dessus.
    


    tu es serieux la?

    Je suis toujours sérieux...


    Si dans le getter il n'y a pas de "retain autorelease", alors la methode dealloc appelée lors du release de l'objet foo aura pour effet la destruction de l'objet pointé par sa variable d'instance clef. Et par conséquent fooKey pointera sur un objet détruit...


    ... Et appeler la méthode bar sur un objet détruit aura très certainement un effet explosif  ;)




    Par contre en inversant les 2 dernières lignes de mon exemple il n'y aura pas de plantage. Mais c'est prendre un risque de contraindre le développeur à  faire attention au sens dans lequel il libère les objets... Et c'est même parfois compliqué dans du "vrai" code.


  • cyranocyrano Membre
    14:41 modifié #13
    eh bin...

    <br />FooObject *foo = [[FooObject alloc] init];<br />....<br />id fooKey = [foo clef];<br /><br /><br />[fookey retain]; //je veux etre responsable puisque je vais detruire le conteneur<br />[foo release];<br />.....<br />[fooKey bar]; <br />....<br />[foodKey release]; //je libere foodKey, (autorelease si absolument necessaire seulement)<br /><br />.
    


    voila +propre et +lisible....
  • zoczoc Membre
    14:41 modifié #14
    Certes, dans un bout de code aussi simple, c'est facile. Ce n'est pas toujours si simple...

    Et puis ta solution va à  l'encontre des préconisations d'apple: C'est l'objet FooObject qui est responsable de la gestion mémoire des objets retournés par ses getters (il en est propriétaire puisque leur nom ne commence ni par init, ni par copy), l'utilisateur de ses méthodes ne doit pas effectuer d'appels à  retain/release lorsqu'il ne désire pas conserver l'objet au delà  de l'itération courante de la boucle de messages.

    Maintenant, tant que c'est dans du code privé, c'est ton problème. Mais le jour où tu publieras un framework, les utilisateurs de ton framework n'accepteront certainement la contrainte que tu leur impose, puisque les autres frameworks n'ont pas cette contrainte.
  • cyranocyrano Membre
    14:41 modifié #15
    tiens une question?

    ce code est t'il valide?


    NSArray *array = ....

    id obj = [array objectAtIndex:5];

    [array release];
    [obj bar];

  • 14:41 modifié #16
    dans 1304153979:

    tiens une question?

    ce code est t'il valide?


    NSArray *array = ....

    id obj = [array objectAtIndex:5];

    [array release];
    [obj bar];


    Non et Oui. Enfin ça dépend de bien d'autres choses.. Déjà  d'où vient 'obj'? Est-ce qu'il a été instancié au moment où tu as instancié la array? Dans ce cas, le code reste valide.

    <br />NSArray *array = [[NSArray alloc] initWithObjects:[Foo foo], [Foo foo], ....,nil];<br />// [Foo foo] retourne une instance autoreleased de Foo.<br />// Mais dès lors que l&#039;on ajoute cette instance à  une array, cette dernière va la retenir automatiquement.<br />// Ce qui équivaut à  avoir fait :<br />// id obj = [Foo foo];<br />// [obj retain];<br /><br />id obj = [array objectAtIndex:5];<br />[array release]; // les obj sont donc release chacun leur tour. Mais il reste notre retain+autorelease lors de l&#039;utilisation de la méthode de classe &#039;foo&#039;<br />[obj bar]; // ne plante pas... tous les obj seront release à  la fin de la runloop<br />
    


    Quand bien même, je trouve ça assez moche comme façon d'écrire. Pour moi si tu accèdes à  un objet d'une array, mais que tu l'utilises après avoir release cette array, berk.
    Le code le plus lisible reste de toujours de release en dernier les objets que l'on instancie en premier.
  • cyranocyrano Membre
    14:41 modifié #17

    Quand bien même, je trouve ça assez moche comme façon d'écrire. Pour moi si tu accèdes à  un objet d'une array, mais que tu l'utilises après avoir release cette array, berk.


    et que fait zoc dans son exemple?

    il utilise une variable d'instance après avoir détruit l'objet.

    je suis entierement d'accord c'est beurk, d'ou l'écriture explicite et non implicite.
  • laudemalaudema Membre
    14:41 modifié #18
    dans 1304153979:

    tiens une question?

    ce code est t'il valide?


    NSArray *array = ....

    id obj = [array objectAtIndex:5];

    [array release];
    [obj bar];

    Pour moi non car tu n'as pas fait alloc/retain/copy sur array donc tu n'as pas à  faire release, ou alors je n'ai pas bien compris les règles régissant la mémoire dans Cocoa, ce qui n'est pas impossible..
  • cyranocyrano Membre
    14:41 modifié #19
    Je précise la question

    objectAtIndex: fait il un retain/autorelease?

    Zoc le laissait sous entendre
  • avril 2011 modifié #20
    Bonne question, dans la logique des choses oui.

    Un moyen simple de tester:
    <br /><br />NSString* myString = [[NSString alloc] initWithString:@&quot;foo&quot;];<br />NSArray* array = [[NSArray alloc] initWithObject:myString];<br /><br />[myString release], myString=nil;<br /><br />myString = [array objectAtIndex:0];<br />[array release];<br /><br />NSLog(@&quot;%@&quot;,[myString componentsSeparatedByString:@&quot;o&quot;]);<br />
    
    ;

    Si ça ne plante pas, c'est donc que objectAtIndex: fait bien un retain/autorelease. Et ça confirme donc une certaine sécurité pour ceux qui codent mal  :D (dans le cas d'une appli non multi-thread encore une fois.)

    Edit: et effectivement, j'ai bien un résultat. Donc objectAtIndex: fait un retain/autorelease.
  • laudemalaudema Membre
    avril 2011 modifié #21
    Peut être que, comme l'expliquait el Gator dans un autre post, ça ne crashe pas parce que même si l'objet est relaché tant que le pointeur n'est pas occupé par un autre objet il peut continuer à  répondre ?
    Tout laisse penser que Cocoa affecte une constant @foo et qu'elle reste disponible...
    <br />&nbsp; &nbsp; &nbsp; &nbsp; NSString *foo = @&quot;foo&quot;;<br />	printf(&quot;foo: %p rc: %i&#092;n&quot;, foo, (int)[foo retainCount]);<br />//foo: 0x100001060 rc: -1<br />	NSString* myString = [[NSString alloc] initWithString:@&quot;foo&quot;];<br />	NSArray* array = [[NSArray alloc] initWithObjects:myString, nil];<br />	printf(&quot;myString: %p rc: %i&#092;n&quot;, myString, (int)[myString retainCount]);<br />//myString: 0x100001060 rc: -1<br />&nbsp; &nbsp; &nbsp; &nbsp; [myString release], myString=nil;<br />	printf(&quot;myString: %p rc: %i&#092;n&quot;, myString, (int)[myString retainCount]);<br />//myString: 0x0 rc: 0<br />	myString = [array objectAtIndex:0];<br />	[array release];<br />	printf(&quot;myString: %p rc: %i&#092;n&quot;, myString, (int)[myString retainCount]);<br />//myString: 0x100001060 rc: -1<br />	[myString release];<br />	printf(&quot;%s&#092;n&quot;, [myString UTF8String]);<br />//foo<br />	NSString *otherString = [[NSString alloc] initWithString:@&quot;foo&quot;];<br />	printf(&quot;otherString: %p rc: %i&#092;n&quot;, otherString, (int)[otherString retainCount]);<br />//otherString: 0x100001060 rc: -1<br />	NSString *thirdString = [[NSString alloc] initWithString:@&quot;foo&quot;];<br />	printf(&quot;thirdString: %p rc: %i&#092;n&quot;, thirdString, (int)[thirdString retainCount]);<br />//thirdString: 0x100001060 rc: -1<br />	myString = [[NSString alloc] initWithString:@&quot;bar&quot;];<br />	printf(&quot;myString: %p rc: %i&#092;n&quot;, myString, (int)[myString retainCount]);<br />//myString: 0x100001080 rc: -1<br />
    

    Quelque soit la nouvelle string faite avec @foo elle a la même adresse (0x100001060) et un retainCount de -1 qui doit être la manière dont Cocoa gère les constantes...

    Rien à  faire, je ne me fierais pas à  ça ...
  • laudemalaudema Membre
    mai 2011 modifié #22
    Je dirais même plus
    <br />	NSString *foo = @&quot;foo&quot;;<br />	NSString* myString = [[NSString alloc] initWithFormat:@&quot;%@&quot;,foo];<br />	NSArray* array = [[NSArray alloc] initWithObjects:myString, nil];<br />	[myString release];<br />	myString = nil;<br />	myString = [array objectAtIndex:0];<br />	printf(&quot;%s&#092;n&quot;, [myString UTF8String]);//foo<br />	[array release];<br />	printf(&quot;%s&#092;n&quot;, [myString UTF8String]);<br />	//EXC_BAD_ACCESS..<br />
    

    lauDupont | lauDupond
  • zoczoc Membre
    avril 2011 modifié #23
    dans 1304162401:

    objectAtIndex: fait il un retain/autorelease?

    Je vais répondre moi même a la question puisque je viens de tester... NON

    Faire le test avec un objet NSString n'est pas significatif car les constantes chaines sont réutilisées tant que possible et par conséquent jamais détruites.

    J'ai fait mon test avec un NSNumber initialisé avec un float aléatoire (histoire de ne pas obtenir un objet provenant d'un cache quelconque), et effectivement le retain count reste inchangé lors d'un appel à  objectAtIndex.

    J'avoue que je suis assez surpris, mais bon, mea culpa, je me suis trompé (même si je persiste à  penser que la version avec retain/autorelease est plus sûre et ne coûte pas grand chose).


    Edit: En fait non, je ne me suis pas trompé, les 2 implémentations sont valables et décrites dans la documentation officielle.
  • MickMick Membre
    14:41 modifié #24
    C'est bien ici que j'avais lu qu'il était bon de COPIER un objet si celui-ci était une "VALEUR" et de RETENIR si c'est une relation...

    When value objects are passed as method arguments or returned from a method, it is common to use a copy instead of the object itself. For example, consider the following method for assigning a string to an object's name instance variable.

    - (void)setName:(NSString *)aName {
        [name autorelease];
        name = [aName copy];
    }

  • CéroceCéroce Membre, Modérateur
    14:41 modifié #25
    Comme il est dit, il est courant de faire une copie. Pourquoi: parce qu'a priori, on ne doit pas modifier l'objet qu'on nous passe en paramètre. C'est un peu comme les paramètres qu'on passe à  une fonction: à  moins qu'ils nous soient passés par référence (par un pointeur), les paramètres deviennent des variables locales.

    Maintenant, l'exemple de code donné est mauvais parce qu'une NSString n'est pas modifiable. S'il passaient une NSMutableString, oui, il serait valable.
  • MickMick Membre
    14:41 modifié #26
    Je suis d'accord avec toi sur le principe : vu que la string n'est pas modifiable, il y a peu d'intérêt à  la copier... Mais alors que fait ce bout de code dans la doc d'Apple sur le memory management ? ..
  • CéroceCéroce Membre, Modérateur
    14:41 modifié #27
    Il ne faut pas forcément prendre la doc d'Apple pour parole d'évangile.
    Ce que je veux dire, c'est que les ingés d'Apple sont souvent plus balèzes que nous autres, mais eux aussi ça les ennuie d'écrire des pages de doc plutôt que coder des trucs intéressants. Alors, ils font au plus simple, et parfois leurs exemples illustrent mal leur propos.
  • MickMick Membre
    14:41 modifié #28
    Ok.

    Donc si on résume les choses :
    un accesseur "robuste" qui évite les crashs dans un code du genre :
    <br />//obj est un objet ayant une variable d&#039;instance valeur <br />Valeur *lAncienneValeur=[obj laValeur];<br />Valeur *uneNouvelleValeur=[Valeur valeur];<br />[obj setValeur:uneNouvelleValeur];<br />[lAncienneValeur setName:@&quot;nom&quot;]; //Craaashh<br />
    

    Si on veut éviter cela, il faut donc un getter de la forme
    <br />- (Valeur *)valeur {<br />return [[valeur retain] autorelease];<br />}<br />
    

    et le setter sera de la forme :
    <br />- (void)setValeur:(Valeur *)uneValeur {<br />[valeur release];<br />valeur=[uneValeur retain];<br />}<br />
    

    Par contre, il y a perte de performance en cas d'accès fréquents au getter.

    Est-ce vos pratiques habituelles ? ou bien évitez-vous le premier code par exemple en retenant vous-même lAncienneValeur ou en la copiant pour l'utiliser et ainsi utiliser les accesseurs "classiques" :
    <br />- (Valeur *)valeur {<br />return valeur;<br />}<br />- (void)setValeur:(Valeur *)uneValeur {<br />[valeur release];<br />valeur=[uneValeur retain];<br />}<br />
    
  • FloFlo Membre
    14:41 modifié #29
    Pour moi c'est la responsabilité de l'appelant d'effectuer un retain sur l'ancienne valeur.
    Ce dernier sait pertinemment qu'il va redéfinir la valeur d'obj et devient donc le nouveau propriétaire de l'ancienne valeur qu'il souhaite conserver.

    Personnellement j'utilise souvent cette logique qui correspond à  l'implémentation des accesseurs générés par le compilo suite à  l'utilisation de :
    @property(retain, nonatomic)
    


    Cependant, dans le cas d'une application multi-thread et d'une variable identifiée comme "à  accès concurrents", il semble en effet beaucoup plus logique d'utiliser :
    @property(retain)
    


    qui va automatiquement effectuer un [[valeur retain] autorelease] dans le getter.
  • AliGatorAliGator Membre, Modérateur
    14:41 modifié #30
    Personnellement :
    • Je crois n'avoir quasiment jamais utilisé [tt]-copy[/tt] ou presque -- à  part pour des blocks (la nouveauté de iOS4 et OSX.6) qui est un cas un peu particulier (et que tu n'utiliseras pas de suite si tu ne maà®trises pas déjà  tout le reste, tu as le temps !). J'ai rarement eu de cas où un "copy" était nécessaire. Ceci dit cela ne me surprendrait pas que tout le framework Cocoa implémente le CopyOnWrite et donc que sur un objet non mutable, un copy soit l'équivalent pratique d'un release, mais bon
    • Comme j'utilise fortement les @property (et vous engage à  faire de même) et que dans la foulée j'utilise donc bien souvent également @synthesize, cela fait une éternité que je n'ai plus codé moi-même des getters/setters. Je laisse le compilateur me les générer à  la volée, donc c'est lui qui se charge de faire le bon code, avec retain+autorelease pour le getter, avec les @synchronzed si la @property est atomic, avec les appels nécessaires pour le KVO, avec les vérifications qu'il faut, et tout.
    • Si j'ai vraiment à  implémenter un getter, je fais retain+autorelease. Bon c'est vrai en pratique je ne le fais pas toujours, mais quand je ne le fais pas c'est parce que j'oublie ou code trop vite (et non volontairement en me disant "celui qui appellera mon getter n'a qu'à  penser lui-même à  faire les release"), car il est évident que ce n'est pas à  l'utilisateur du getter de gérer ça.
    • Si vraiment j'ai à  implémenter le setter moi-même, je ne le fais pas toujours KVO-Compliant (souvent j'ai la flemme, j'avoue, surtout pour les rares fois où j'ai à  coder le setter moi-même quand c'est pas @synthesize qui le fait), par contre je vérifie toujours que la nouvelle valeur n'est pas la même (comprendre : le pointeur ne représente pas la même adresse mémoire) avant de faire le release suivi du retain (comme le préconise et l'explique la doc Apple sur la gestion mémoire)
  • FloFlo Membre
    14:41 modifié #31
    Comme j'utilise fortement les @property (et vous engage à  faire de même) et que dans la foulée j'utilise donc bien souvent également @synthesize, cela fait une éternité que je n'ai plus codé moi-même des getters/setters. Je laisse le compilateur me les générer à  la volée, donc c'est lui qui se charge de faire le bon code, avec retain+autorelease pour le getter, avec les @synchronzed si la @property est atomic, avec les appels nécessaires pour le KVO, avec les vérifications qu'il faut, et tout.


    +1 pour les @property, par contre je ne savais pas que le getter généré par un @property(retain, nonatomic) faisait aussi un retain+autorelease...
Connectez-vous ou Inscrivez-vous pour répondre.