Digamos que eu tenha uma classe chamada SomeClass
com um string
nome de propriedade:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
Entendo que esse nome pode ser atribuído a NSMutableString
, caso em que isso pode levar a um comportamento incorreto.
- Para cadeias de caracteres em geral, é sempre uma boa ideia usar o
copy
atributo em vez deretain
? - Uma propriedade "copiada" é menos eficiente do que uma propriedade "retida"?
objective-c
cocoa
cocoa-touch
PlagueHammer
fonte
fonte
name
ser lançadodealloc
ou não?Respostas:
Para atributos cujo tipo é uma classe de valor imutável que está em conformidade com o
NSCopying
protocolo, você quase sempre deve especificarcopy
em sua@property
declaração. Especificarretain
é algo que você quase nunca deseja em tal situação.Aqui está o porquê você deseja fazer isso:
O valor atual da
Person.name
propriedade será diferente dependendo se a propriedade for declaradaretain
oucopy
- será@"Debajit"
se a propriedade estiver marcadaretain
, mas@"Chris"
se a propriedade estiver marcadacopy
.Como em quase todos os casos você deseja impedir a mutação dos atributos de um objeto pelas costas, marque as propriedades que os representam
copy
. (E se você mesmo escrever o setter em vez de usá-@synthesize
lo, lembre-se de usá- lo emcopy
vez de usá-retain
lo.)fonte
NSMutableString
, exceto como um tipo de "construtor de string" transitório (do qual eu imediatamente tiro uma cópia imutável). Eu preferiria que fossem tipos discretos - mas permitirei que o fato de que a cópia seja livre para reter se a sequência original não for mutável atenua a maior parte da minha preocupação.A cópia deve ser usada para o NSString. Se for Mutável, será copiado. Se não estiver, apenas será retido. Exatamente a semântica que você deseja em um aplicativo (deixe o tipo fazer o que é melhor).
fonte
NSString
propriedade declarada comocopy
receberá deretain
qualquer maneira (se for imutável, é claro). Outro exemplo em que posso pensar éNSNumber
.Sim - em geral, sempre use o atributo copy.
Isso ocorre porque sua propriedade NSString pode receber uma instância NSString ou uma instância NSMutableString e, portanto, não podemos realmente determinar se o valor que está sendo passado é um objeto imutável ou mutável.
Se sua propriedade está sendo transmitida para uma instância NSString , a resposta é " Não " - a cópia não é menos eficiente do que reter.
(Não é menos eficiente, porque o NSString é inteligente o suficiente para não executar uma cópia.)
Se sua propriedade receber uma instância de NSMutableString , a resposta será " Sim " - a cópia é menos eficiente que a retenção.
(É menos eficiente porque uma alocação e cópia de memória real deve ocorrer, mas isso é provavelmente uma coisa desejável.)
De um modo geral, uma propriedade "copiada" tem o potencial de ser menos eficiente - no entanto, com o uso do
NSCopying
protocolo, é possível implementar uma classe que é "tão eficiente" para copiar quanto para reter. As instâncias NSString são um exemplo disso.Você sempre deve usar
copy
quando não deseja que o estado interno da propriedade seja alterado sem aviso. Mesmo para objetos imutáveis - objetos imutáveis escritos corretamente manipularão a cópia com eficiência (consulte a próxima seção sobre imutabilidade eNSCopying
).Pode haver motivos de desempenho para os
retain
objetos, mas ele vem com uma sobrecarga de manutenção - você deve gerenciar a possibilidade de o estado interno mudar fora do seu código. Como se costuma dizer - otimizar por último.Não - use
copy
. Se sua classe é realmente imutável, é uma boa prática implementar oNSCopying
protocolo para fazer com que ela retorne quandocopy
for usada. Se você fizer isto:copy
.copy
anotação torna seu próprio código mais sustentável - acopy
anotação indica que você realmente não precisa se preocupar com esse objeto alterando o estado em outro lugar.fonte
Eu tento seguir esta regra simples:
Desejo manter o valor do objeto no momento em que o atribui à minha propriedade? Use cópia .
Eu quero me apegar ao objeto e não me importo com quais são seus valores internos atualmente ou serão no futuro? Use forte (reter).
Para ilustrar: Eu quero me apegar ao nome "Lisa Miller" ( cópia ) ou quero me apegar à pessoa Lisa Miller ( forte )? Seu nome pode mais tarde mudar para "Lisa Smith", mas ela ainda será a mesma pessoa.
fonte
Através deste exemplo, copiar e reter pode ser explicado como:
se a propriedade for do tipo copy,
uma nova cópia será criada para a
[Person name]
sequência que conterá o conteúdo dasomeName
sequência. Agora qualquer operação nasomeName
string não terá efeito[Person name]
.[Person name]
esomeName
strings terão diferentes endereços de memória.Mas em caso de retenção,
ambos
[Person name]
manterão o mesmo endereço de memória da sequência de nomes de som, apenas a contagem de retenção da sequência de nomes de nomes será incrementada em 1.Portanto, qualquer alteração na cadeia de caracteres de um nome será refletida na
[Person name]
cadeia de caracteres.fonte
Certamente, colocar 'copiar' em uma declaração de propriedade não deve ser usado em um ambiente orientado a objetos, onde objetos na pilha são passados por referência - um dos benefícios que você obtém aqui é que, ao alterar um objeto, todas as referências a esse objeto veja as últimas alterações. Muitos idiomas fornecem 'ref' ou palavras-chave semelhantes para permitir que tipos de valor (ou seja, estruturas na pilha) se beneficiem do mesmo comportamento. Pessoalmente, eu usaria a cópia com moderação e, se considerasse que um valor de propriedade deveria ser protegido de alterações feitas no objeto do qual foi atribuído, poderia chamar o método de cópia desse objeto durante a atribuição, por exemplo:
Obviamente, ao projetar o objeto que contém essa propriedade, apenas você saberá se o design se beneficia de um padrão em que as atribuições tiram cópias - Cocoawithlove.com tem o seguinte a dizer:
"Você deve usar um acessador de cópia quando o parâmetro setter puder ser mutável, mas não for possível alterar o estado interno de uma propriedade sem aviso " ", portanto, o julgamento sobre se você pode suportar o valor de alterar inesperadamente é seu. Imagine este cenário:
Nesse caso, sem usar a cópia, nosso objeto de contato recebe o novo valor automaticamente; se o utilizássemos, teríamos de garantir manualmente que as alterações fossem detectadas e sincronizadas. Nesse caso, reter semântica pode ser desejável; em outro, a cópia pode ser mais apropriada.
fonte
fonte
Você deve usar copiar o tempo todo para declarar a propriedade NSString
Você deve lê-los para obter mais informações sobre se ela retorna uma sequência imutável (no caso de uma sequência mutável ter sido passada) ou retorna uma sequência de caracteres retida (no caso de uma sequência imutável)
Referência do Protocolo NSCopying
Objetos de valor
fonte
Como o nome é (imutável)
NSString
, copiar ou reter não faz diferença se você definir outroNSString
como nome. Em outra palavra, a cópia se comporta exatamente como reter, aumentando a contagem de referência em um. Eu acho que é uma otimização automática para classes imutáveis, uma vez que são imutáveis e não precisam ser clonadas. Mas quando aNSMutalbeString
mstr
é definido como o nome, o conteúdo demstr
será copiado por uma questão de correção.fonte
Se a sequência for muito grande, a cópia afetará o desempenho e duas cópias da sequência grande usarão mais memória.
fonte