Pourquoi copie-t-on les NSString ?

NeofelisNeofelis Membre
02:19 modifié dans Objective-C, Swift, C, C++ #1
Dans mes livres objective-c on utilise la plupart du temps copy dans les setters plutôt que retain pour les NSString. Quelle en est la raison ?

Réponses

  • BunoBuno Membre
    02:19 modifié #2
    ça dépend des cas d'utilisation:
    - avec retain, tu retiens la référence: tu as donc un seul et même objet
    - avec copy, tu copies la string: tu as donc 2 objets différents

    Dans le 1er cas, toute modification implique tout le monde, pas dans le second
  • NeofelisNeofelis Membre
    02:19 modifié #3
    Oui mais ce que je voulais savoir c'est pourquoi on utilisait en général copy avec les NSString. Après une petite recherche je pense que c'est parce que NSString est une classe non "mutable"...
  • MickMick Membre
    02:19 modifié #4
    Bonjour,

    On copie normalement les variables d'instances de type "value" => Ce qui t'intéresse n'est pas l'objet lui-même (le pointeur vers la zone mémoire), mais sa valeur. Du coup, si un objet quelconque change la valeur de l'objet, c'est mauvais. Du fait, en utilisant une copie, tu évite ce soucis. (ceci est vrai pour toutes tes "values" de ta couche donnée). Par opposition, pour les "relationships", ce qui t'interesse est l'adresse de l'objet, les valeurs de ses variables d'instance pouvant êtres modifiées par d'autres objets => On retient.

    Ca c'est pour le principe. Mais dans les faits, on avait d'ailleurs eu une discussion là -dessus relative aux accesseurs, une NSString, un NSData, une NSDate ... n'étant pas modifiables a priori, il n'y a pas de raison particulière de les copier, donc la retenir peut suffire.

    Personnellement, je n'écris plus mes accesseurs (@property, @synthetize sauf cas particuliers), mais la doc d'Apple indique http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAccessorMethods.html

  • CéroceCéroce Membre, Modérateur
    02:19 modifié #5
    dans 1306143889:

    - avec retain, tu retiens la référence: tu as donc un seul et même objet
    - avec copy, tu copies la string: tu as donc 2 objets différents


    Sauf que pour les objets immutables, -[copy] est implémenté par un -[retain].
    Dixit le livre Cocoa Design Patterns.
    Ce qui parait cohérent puisqu'il n'y a aucune intérêt à  avoir exactement le même objet en mémoire s'il ne peut pas être modifié.
  • AliGatorAliGator Membre, Modérateur
    02:19 modifié #6
    Je crois que j'ai jamais utilisé [tt]copy[/tt] de ma vie même dans mes gros projets. A part pour faire des copies sur des blocks (message équivalent à  appeler la fonction Block_copy) mais c'est un peu particulier.
  • Eddy58Eddy58 Membre
    02:19 modifié #7
    J'utilise parfois Copy pour transformer un objet mutable en non mutable. (Ou l'inverse avec mutableCopy)
    Ou alors aussi pour la même raison, dans un accesseur qui reçoit un mutable pour le fixer en non mutable.
  • NeofelisNeofelis Membre
    02:19 modifié #8
    Donc si je comprends bien il n'y a aucun intérêt à  faire un copy d'une chaà®ne (NSString) plutôt qu'un retain dans un setter ?

    J'ai du mal à  comprendre dans ce cas pourquoi on dit dans mon bouquin que le type "copy" (pour les properties) est adapté pour les NSString...  ???

    Un peu paumé pour le coup...
  • AliGatorAliGator Membre, Modérateur
    02:19 modifié #9
    Oui c'est bizarre. C'est quoi ton bouquin ?
  • NeofelisNeofelis Membre
    mai 2011 modifié #10
    dans 1306189750:

    Oui c'est bizarre. C'est quoi ton bouquin ?


    J'en ai plusieurs mais je crois que c'est "Objective-C 2.0 : Le Guide de survie" de Pejvan Beigui. Par contre je n'arrive plus à  retrouver le passage en question après recherche ce matin... (de là  à  dire que j'ai rêvé... ^^)

    Ceci dit j'ai rencontré une autre étrangeté hier soir en faisant des tests. J'ai créé un objet NSString et affiché ensuite son retainCount qui m'affiche 4294967295 (qui correspond à  UINT_MAX)... Après une petite recherche sur le net et d'après ce que j'ai compris c'est que les objets de NSString sont des objets statiques et le fait de "retenir" ou "libérer" ce type d'objet n'a pas de sens... du coup ça sert à  rien de faire des retain et release dans les setters de NSString ? C'est pas très clair tout ça...

  • AliGatorAliGator Membre, Modérateur
    02:19 modifié #11
    En fait NSString est un cas très particulier (qu'il n'est sans doute pas bon de prendre en exemple même si c'est tentant car la première classe qui nous vient à  l'esprit), car c'est un class cluster qui sait gérer les NSString placées en dur dans ton code (et du coup qui seront encapsulées dans ton exécutable final, et pour lesquelles un retain/release n'a aucun effet) mais aussi des NSString qui sont construites dynamiquement (pour qui là  le retain/release est important)...

    - Par exemple [tt]NSString* stat = @Chaà®ne statique;[/tt] étant une chaà®ne statique, constante, connue à  la compilation, sera compilée en dur dans le code (un "retain" ou un "release" dessus n'a aucun effet, c'est là  le cas un peu particulier)
    - Alors que [tt]NSString* dyn = [NSString stringWithFormat:@Chaà®ne dynamique %d !,val];[/tt] est une chaà®ne qui sera créé dynamiquement (forcément, vu que là  on peut pas prédire sa valeur à  la compilation) et donc pour le coup le retain et le release sont nécessaires et feront le boulot attendu.

    NSString est loin d'être la classe la plus adéquate pour comprendre les mécanisme sous-jacents d'Objective-C comme la gestion mémoire, tellement il peut y avoir de cas particulier avec elle (le fait que ce soit un class cluster, le fait que les chaà®nes peuvent être statiquement allouées...).
    En pratique tu n'as pas à  te soucier de tout ça normalement : tu utilises NSString de façon "intuitive" et classique comme n'importe quelle autre NSObject, tu n'as pas besoin de savoir que c'est un class cluster, si ta chaà®ne est statique ou dynamique, ou quoi : tu lui appliques les règles de gestion mémoire classique et c'est tout (c'est là  la beauté du modèle de gestion mémoire ObjC, également).
    Mais sous le capot cela fait partie des classes qui sont le plus optimisées et gérant des cas bien particuliers (car le langage ObjC lui-même te permet de créer des NSString directement avec la syntaxe [tt]@xxx[/tt], ce "@" est une notation incluse dans le langage), du coup c'est loin d'être l'exemple le plus simple pour comprendre comment ça marche vu toutes les subtilités qu'il y a avec cette classe en interne.

    Donc, pour répondre à  ta question : OUI il faut faire les retain et release dans les setters de NSString, car c'est nécessaire si ta NSString est allouée dynamiquement (genre stringWithFormat). Et ça ne fait pas de mal si elle est allouée statiquement donc autant uniformiser le code (d'autant que tu ne peux pas savoir par code si tu es dans un cas où dans l'autre et qu'il n'y aurait aucun intérêt à  faire la distinction de toute façon).

    Si tu veux faire des tests et des essais à  regarder le retainCount (qui ne doit servir qu'à  des fins de debug de toute façon) et autre pour mieux comprendre ce qui se passe sous le capôt de Cocoa, je te conseille de prendre autre chose que NSString pour faire tes observations (par exemple crée une classe perso dérivant de NSObject), car NSString est un cas bien trop particulier et spécifique.
  • NeofelisNeofelis Membre
    02:19 modifié #12
    Merci pour cette réponse très claire :)
Connectez-vous ou Inscrivez-vous pour répondre.