@property semi-privées en mode copy
colas_
Membre
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 :
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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.
@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 !
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.
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.
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.
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 ?
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).
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
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.
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, ...)
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...)
Me conseillez-vous :
- de ne rien mettre ?
- de mettre weak ?
(- de mettre strong)
Merci !
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 !
weak
On conserve simplement une référence vers l'objet. Ceci implique qu'un autre objet doit absolument le retenir.
strong
Dans ce cas, le nouvel objet est retenu et l'ancien est relâché.
(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
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 ?
Réponse :
En plus de la réponse de @Aligator, ne pas rajouter un @syntesize.
(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 !