@property semi-privées en mode copy

Bonjour,


 


Pourquoi le cas de figure suivant bugue-t-il, et quelle est la meilleure façon de procéder ?


 


Merci !



//
// Test.h
//

#import <Foundation/Foundation.h>

@interface Test : NSObject

@property (nonatomic, readonly) NSString * myProperty ;

@end


et



//
// Test.m
//

#import "Test.h"

@interface Test ()

@property (nonatomic, copy, readwrite) NSString * myProperty ;

@end

@implementation Test

@end

L'erreur affichée est  : 


Réponses

  • CéroceCéroce Membre, Modérateur

    Quand on ne précise pas weak, strong, ou copy, par défaut c'est strong.


    Là , tu as une incohérence entre le .h et le .m.


    Précise copy dans le .h, ça devrait fonctionner.


  • colas_colas_ Membre
    septembre 2013 modifié #3

    @Céroce : merci ! ça marche bien.


     


    Pour info, confirmes-tu que si une @property est readonly, alors ça ne changera rien qu'elle soit weak ou strong ?


    (évidemment, sauf dans le cas où derrière la même @property est déclarée en readwrite)


  • J'espère qu'il vas pas le confirmer :). readonly/readwrite n'a aucun rapport avec weak/strong/assign. il faut choisir weak/strong selon si l'objet doit ou pas avoir une référence forte a la property. 


  • Oui, mais si la @property est readonly, aucune iVar n'est générée donc readonly ou readwrite, ça ne change rien !




  • Oui, mais si la @property est readonly, aucune iVar n'est générée donc readonly ou readwrite, ça ne change rien !




     


    ben non. 


     


    readonly : veux dire que le compilateur ne vas pas générer un setter pour cette iVar y aura juste un getter.


    readwrite : y aura un getter et un setter pour l'iVar.


     


    Dans les deux cas y aura une iVar.

  • AliGatorAliGator Membre, Modérateur
    Je confirme @property(readonly) ne dispense pas de préciser strong ou weak ou autre, cela n'a rien à  voir.

    Et @property(readonly) va tout à  fait générer une variable d'instance. C'est juste que ça ne va pas générer de méthode getter pour cette ivar, mais en interne dans ton .m tu pourras tout à  fait accéder à  cette variable pour l'affecter par exemple.

    @interface Toto : NSObject
    @property(readonly, strong) NSString* name;
    @end

    @implementation Toto
    - (id)init
    {
    self = [super init];
    if (self)
    {
    _name = NSStringFromClass(self.class); // par exemple
    }
    return self;
    }
    Il n'y a que si tu fournis TOUS les accesseurs correspondant à  ta déclaration de @property (dans le cas d'une readonly, juste le getter ; dans le cas d'une readwrite, le getter ET le setter) que le compilateur ne génère pas d'ivar.
  • xylowebxyloweb Membre
    septembre 2013 modifié #8

    mais il n'y a donc pas de retain sur l'objet affecté à  _name ?!


    je croyais que _<var_name> était réservé pour Apple : ne faut-il pas déclarer <var_name>_ plus tôt ?




  • mais il n'y a donc pas de retain sur l'objet affecté à  _name ?!




     SI tu n'utilise pas ARC il te faut un retain, sinon sous ARC les variables d'instances ont les mêmes caractéristiques ARC. ( donc par defaut strong dans ce cas).


     


     




    je croyais que _<var_name> était réservé pour Apple : ne faut-il pas déclarer <var_name>_ plus tôt ?




     


    C'est le nom de l'ivar par defaut généré par le compilateur, justement il préfixé par _ pour le différencier des variables locales, mais on peux changer le nom avec @syntesize

  • AliGatorAliGator Membre, Modérateur
    septembre 2013 modifié #10

    mais il n'y a donc pas de retain sur l'objet affecté à  _name ?!

    Bien sûr que si, l'objet affecté à  _name est retenu par ARC !
    Puisque la @property est marquée (strong), l'ivar associée sera "__strong" et donc ARC va retenir sa valeur. Contrairement à  une @property(weak) où l'ivar générée associée serait "__weak" et ne serait pas retenue.
     

    Je croyais que _<var_name> était réservé pour Apple : ne faut-il pas déclarer <var_name>_ plus tôt ?

    Légende urbaine. (Apple utilise plutôt les "__name" en interne, de mémoire)
    Maintenant même Apple préconise d'utiliser "_var", et de toute façon la synthèse automatique des @property te génère justement une variable du nom de "_name" pour une propriété nommée "name", donc bon...
  • merci à  vous deux pour cette précision (toujours un peu de confusion entre ARC, non-ARC, préconisation de nommage, @synthesize ou pas, ...)


  • colas_colas_ Membre
    septembre 2013 modifié #12

    Dans le cas où j'ai une @property (readonly) dont j'implémente le getter (sans utiliser d'iVar), par exemple


     


    (ce que j'appelle une "pseudo-property" dans mon jargon...)





    @property (nonatomic, readonly) NSString * myName ;

    - (NSString *)myName
    {
    return @Colas ;
    }

    Me conseillez-vous :


    - de ne rien mettre ?


    - de mettre weak ?


    (- de mettre strong)


     


    Merci !


  • CéroceCéroce Membre, Modérateur

    Dans ce cas précis, peu importe, parce que la politique de gestion mémoire s'applique aux setters.


  • Si j'ai bien suivi, le programme va créer une iVar de type NSString.


     


    - si je mets weak : il va la releaser


    - si je mets strong : il la garde, alors qu'elle ne sert à  rien


    - si je mets rien, c'est strong par défaut


     


    En fait, ce que j'aimerais c'est qu'il ne crée même pas d'iVar correspondant à  cette @property !


  • CéroceCéroce Membre, Modérateur
    septembre 2013 modifié #15
    Non, ce n'est pas ça. Pour comprendre, voici en gros à  quoi ça correspond (code pre-ARC):
     
    weak
    On conserve simplement une référence vers l'objet. Ceci implique qu'un autre objet doit absolument le retenir.
    - (void) setName:(NSString *)name
    {
    _name = name;
    }
    strong
    Dans ce cas, le nouvel objet est retenu et l'ancien est relâché.
    - (void) setName:(NSString *)name
    {
    [_name autorelease];
    _name = [name retain];
    }
    (autoreleaser l'objet précédent est surprenant, mais c'est quelque chose que j'avais lu. ça permet au moins de ne pas relâcher un objet qui serait déjà  dans la variable d'instance).
     
    copy
    - (void) setName:(NSString *)name
    {
    [_name autorelease];
    _name = [name copy];
    }
    Voilà . Je ne dis pas que c'est l'implémentation exacte des setters synthétisés, mais ça explique bien le principe.
  • @Céroce : sais-tu si on peut faire en sorte qu'une @property (readonly) ne génère aucune iVar ?


  • samirsamir Membre
    septembre 2013 modifié #17


    @Céroce : sais-tu si on peut faire en sorte qu'une @property (readonly) ne génère aucune iVar ?




    Réponse :


     





    Il n'y a que si tu fournis TOUS les accesseurs correspondant à  ta déclaration de @property (dans le cas d'une readonly, juste le getter ; dans le cas d'une readwrite, le getter ET le setter) que le compilateur ne génère pas d'ivar.



    En plus de la réponse de @Aligator, ne pas rajouter un @syntesize.


  • AliGatorAliGator Membre, Modérateur

    Si j'ai bien suivi, le programme va créer une iVar de type NSString.

    NOOOON il ne va pas en créer !!!

    (J'ai du mal à  comprendre pourquoi c'est si compliquer à  assimiler cette règle, elle est pourtant simple !)


    - Si vous implémentez-vous même tous les accesseurs correspondant à  votre @property, il ne va pas créer d'iVar (et encore heureux). Si vraiment vous en voulez une il faut alors le demander explicitement avec @synthesize
    - Sinon si le compilateur va générer pour vous au moins un des accesseurs, il va générer une ivar (puisqu'il va bien en avoir besoin pour générer son code !)


    Là  t'as une @property(readonly) et tu implémentes tous les accesseurs (tu implémentes le getter, et y'a pas de setter pour un readonly de toute façon), donc il ne va te générer aucun code lui-même (puisque tu fournis toutes les implémentations), donc il ne va pas générer d'ivar.

    C'est tout ce qu'il y a de plus logique, et une règle tout ce qu'il y a de plus simple et déterministe à  comprendre.
  • OK c'est clair !


Connectez-vous ou Inscrivez-vous pour répondre.