Disons que j'ai une classe appelée SomeClass
avec un string
nom de propriété:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
Je comprends que le nom peut être attribué un NSMutableString
auquel cas cela peut conduire à un comportement errant.
- Pour les chaînes en général, est-ce toujours une bonne idée d'utiliser l'
copy
attribut au lieu deretain
? - Une propriété "copiée" est-elle d'une quelconque manière moins efficace qu'une telle propriété "conservée"?
objective-c
cocoa
cocoa-touch
PlagueHammer
la source
la source
name
être libérédealloc
ou non?Réponses:
Pour les attributs dont le type est une classe de valeur immuable conforme au
NSCopying
protocole, vous devez presque toujours le spécifiercopy
dans votre@property
déclaration. Spécifierretain
est quelque chose que vous ne voulez presque jamais dans une telle situation.Voici pourquoi vous voulez faire ça:
La valeur actuelle de la
Person.name
propriété sera différente selon que la propriété est déclaréeretain
oucopy
- ce sera@"Debajit"
si la propriété est marquéeretain
, mais@"Chris"
si la propriété est marquéecopy
.Étant donné que, dans presque tous les cas, vous souhaitez empêcher la mutation des attributs d'un objet derrière son dos, vous devez marquer les propriétés qui les représentent
copy
. (Et si vous écrivez le setter vous-même au lieu de l'utiliser,@synthesize
vous devez vous souvenir de l'utiliser réellementcopy
au lieu deretain
dedans.)la source
NSMutableString
, sauf en tant que type de "générateur de chaîne" transitoire (dont je prends immédiatement une copie immuable). Je préférerais qu'ils soient des types discrets - mais je permettrai que le fait que la copie soit libre de faire une conservation si la chaîne d'origine n'est pas modifiable atténue la plupart de mes inquiétudes.La copie doit être utilisée pour NSString. Si c'est Mutable, alors il est copié. Si ce n'est pas le cas, il est simplement conservé. Exactement la sémantique souhaitée dans une application (laissez le type faire ce qu'il y a de mieux).
la source
NSString
propriété déclaréecopy
sera deretain
toute façon (si elle est immuable, bien sûr). Un autre exemple auquel je peux penser estNSNumber
.Oui - en général, utilisez toujours l'attribut de copie.
Cela est dû au fait que votre propriété NSString peut passer une instance NSString ou une instance NSMutableString , et donc nous ne pouvons pas vraiment déterminer si la valeur transmise est un objet immuable ou modifiable.
Si votre propriété passe une instance NSString , la réponse est " Non " - la copie n'est pas moins efficace que la conservation.
(Ce n'est pas moins efficace car la NSString est suffisamment intelligente pour ne pas réellement effectuer une copie.)
Si votre propriété reçoit une instance NSMutableString, la réponse est " Oui " - la copie est moins efficace que la conservation.
(Il est moins efficace car une allocation de mémoire et une copie réelles doivent se produire, mais c'est probablement une chose souhaitable.)
D'une manière générale, une propriété «copiée» a le potentiel d'être moins efficace - cependant, grâce à l'utilisation du
NSCopying
protocole, il est possible d'implémenter une classe qui est «tout aussi efficace» à copier qu'à conserver. Les instances NSString en sont un exemple.Vous devez toujours l'utiliser
copy
lorsque vous ne voulez pas que l'état interne de la propriété change sans avertissement. Même pour les objets immuables - les objets immuables correctement écrits géreront efficacement la copie (voir la section suivante concernant l'immuabilité etNSCopying
).Les
retain
objets peuvent avoir des raisons de performances , mais ils entraînent une surcharge de maintenance - vous devez gérer la possibilité que l'état interne change en dehors de votre code. Comme on dit - optimisez en dernier.Pas d'utilisation
copy
. Si votre classe est vraiment immuable, il est préférable d'implémenter leNSCopying
protocole pour que votre classe se retourne lorsqu'ellecopy
est utilisée. Si tu fais ça:copy
.copy
annotation rend votre propre code plus facile à gérer - l'copy
annotation indique que vous n'avez vraiment pas besoin de vous soucier du changement d'état de cet objet ailleurs.la source
J'essaie de suivre cette règle simple:
Est-ce que je veux conserver la valeur de l'objet au moment où je l'attribue à ma propriété? Utilisez copie .
Est-ce que je veux m'accrocher à l' objet et je me fiche de ce que ses valeurs internes sont ou seront à l'avenir? Utiliser fort (conserver).
Pour illustrer: Est-ce que je veux conserver le nom "Lisa Miller" ( copie ) ou je veux conserver la personne Lisa Miller ( forte )? Son nom pourrait changer plus tard en "Lisa Smith", mais elle sera toujours la même personne.
la source
Grâce à cet exemple, copier et conserver peut être expliqué comme suit:
si la propriété est de type copie,
une nouvelle copie sera créée pour la
[Person name]
chaîne qui contiendra le contenu de lasomeName
chaîne. Désormais, toute opération sursomeName
chaîne n'aura aucun effet[Person name]
.[Person name]
et lessomeName
chaînes auront des adresses mémoire différentes.Mais en cas de retenue,
les deux
[Person name]
conserveront la même adresse mémoire que pour une chaîne de nom, seul le nombre de chaînes de nom retenu sera incrémenté de 1.Ainsi, tout changement dans une chaîne de nom sera reflété dans la
[Person name]
chaîne.la source
Assurer «copier» sur une déclaration de propriété va sûrement à l'encontre de l'utilisation d'un environnement orienté objet où les objets sur le tas sont passés par référence - l'un des avantages que vous obtenez ici est que, lors du changement d'un objet, toutes les références à cet objet voir les dernières modifications. De nombreuses langues fournissent des mots-clés «ref» ou similaires pour permettre aux types de valeur (c'est-à-dire les structures sur la pile) de bénéficier du même comportement. Personnellement, j'utiliserais la copie avec parcimonie, et si je pensais qu'une valeur de propriété devait être protégée des modifications apportées à l'objet à partir duquel elle était affectée, je pouvais appeler la méthode de copie de cet objet pendant l'affectation, par exemple:
Bien sûr, lors de la conception de l'objet qui contient cette propriété, vous seul saurez si la conception bénéficie d'un modèle dans lequel les affectations prennent des copies - Cocoawithlove.com a ce qui suit à dire:
"Vous devez utiliser un accesseur de copie lorsque le paramètre setter peut être modifiable, mais vous ne pouvez pas faire changer l'état interne d'une propriété sans avertissement " - donc vous décidez si vous pouvez supporter la valeur à modifier de manière inattendue. Imaginez ce scénario:
Dans ce cas, sans utiliser de copie, notre objet contact prend automatiquement la nouvelle valeur; si nous l'utilisions, cependant, nous devrions nous assurer manuellement que les modifications ont été détectées et synchronisées. Dans ce cas, conserver la sémantique peut être souhaitable; dans un autre, une copie pourrait être plus appropriée.
la source
la source
Vous devez utiliser la copie tout le temps pour déclarer la propriété NSString
Vous devriez les lire pour plus d'informations sur le fait qu'elle renvoie une chaîne immuable (au cas où une chaîne mutable a été transmise) ou renvoie une chaîne conservée (dans le cas où une chaîne immuable a été transmise)
Référence du protocole NSCopying
Objets de valeur
la source
Étant donné que le nom est un (immuable)
NSString
, copier ou conserver ne fait aucune différence si vous en définissez un autreNSString
sur name. Dans un autre mot, la copie se comporte comme la conservation, augmentant ainsi le nombre de références. Je pense que c'est une optimisation automatique pour les classes immuables, car elles sont immuables et n'ont pas besoin d'être clonées. Mais quand aNSMutalbeString
mstr
est défini sur name, le contenu demstr
sera copié par souci d'exactitude.la source
Si la chaîne est très volumineuse, la copie affectera les performances et deux copies de la chaîne volumineuse utiliseront plus de mémoire.
la source