@property retém, atribui, copia, não atômico no Objective-C

214

Como alguém que é novo no Objective-C, alguém pode me dar uma visão geral da retenção, atribuição, cópia e qualquer outra coisa que esteja faltando, que siga a diretiva @property? O que eles estão fazendo e por que eu gostaria de usar um sobre o outro?

Mark Reid
fonte
1
Nome da Apple para estes é "atributos" ou "atributos de propriedade"
rei Nevan

Respostas:

273

O artigo vinculado pelo MrMage não está mais funcionando. Então, aqui está o que eu aprendi na minha (muito) curta codificação no Objective-C:

atômico vs. atômico - "atômico" é o padrão. Sempre use "não atômico". Não sei por que, mas o livro que li dizia que "raramente há uma razão" para usar "atômico". (BTW: O livro que li é o livro "Programação iOS" do BNR.)

readwrite vs. readonly - "readwrite" é o padrão. Quando você @ sintetiza, um getter e um setter serão criados para você. Se você usar "somente leitura", nenhum setter será criado. Use-o para um valor que você nunca deseja alterar após a instanciação do objeto.

reter x copiar x atribuir

  • "atribuir" é o padrão. No setter criado por @synthesize, o valor será simplesmente atribuído ao atributo. Meu entendimento é que "atribuir" deve ser usado para atributos que não são ponteiros.
  • "reter" é necessário quando o atributo é um ponteiro para um objeto. O setter gerado por @synthesize reterá (também conhecido como adicionar uma contagem de retenções) o objeto. Você precisará liberar o objeto quando terminar.
  • "cópia" é necessária quando o objeto é mutável. Use isso se você precisar do valor do objeto como está neste momento e não desejar que esse valor reflita as alterações feitas por outros proprietários do objeto. Você precisará liberar o objeto quando tiver terminado porque está mantendo a cópia.
Blamdarot
fonte
@Blamdarot - eu preciso liberá-lo com ARC bem
Dejell
10
@ Odelya - Não. Se você liberar enquanto estiver usando o ARC, acredito que receberá um erro do compilador.
Blamdarot
52
"Sempre use não atômico" é um mau conselho. Você deve saber do que está desistindo ao usar o não-atômico.
Jesse Rusak # 24/13
7
Acordado. Em particular, muitas pessoas parecem não saber que valores não-atômicos não são retidos automaticamente pelo getter. não-atômico é geralmente apropriado, mas a programação do culto à carga raramente é.
Catfish_Man
9
O aconselhamento para deixar o padrão atomicé tão ruim quanto o aconselhamento nonatomic. Nenhuma das opções é a "correta"; portanto, os designers de idiomas optaram pelo mais seguro das duas soluções. De fato, nonatomicgeralmente é a melhor escolha, pois omite bloqueios de linha extremamente caros. O único motivo para usar atomicé se sua propriedade pode ser configurada a partir de vários encadeamentos (nesse caso, sua omissão pode levar a uma liberação excessiva ou um vazamento).
Adam Kaplan
295

Antes de conhecer os atributos de @property, você deve saber qual é o uso de @property.

  • O @property oferece uma maneira de definir as informações que uma classe pretende encapsular. Se você declarar um objeto / variável usando @property , esse objeto / variável estará acessível para outras classes que importam sua classe.

  • Se você declarar um objeto usando @property no arquivo de cabeçalho, precisará sintetizá-lo usando @synthesize no arquivo de implementação. Isso torna o objeto compatível com KVC . Por padrão, o compilador sintetizará métodos de acessador para esse objeto.

  • Os métodos de acesso são: setter e getter.

Exemplo: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Agora o compilador sintetizará métodos de acessador para o nome .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Lista de atributos de @property

    atômico, não atômico, reter, copiar, somente leitura, escrever novamente, atribuir, forte, getter = método, setter = método, unsafe_unretained

  • atômico é o comportamento padrão. Se um objeto é declarado como atômico, ele se torna seguro para threads. Segura por thread significa que, por vez, apenas um thread de uma instância específica dessa classe pode ter o controle sobre esse objeto.

Se o encadeamento estiver executando o método getter, outro encadeamento não poderá executar o método setter nesse objeto. Está lento.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic não é seguro para threads. Você pode usar o atributo de propriedade não atômica para especificar que os acessadores sintetizados simplesmente configuram ou retornam um valor diretamente, sem garantias sobre o que acontece se esse mesmo valor for acessado simultaneamente a partir de diferentes threads.

Por esse motivo, é mais rápido acessar uma propriedade não atômica do que uma atômica.

@property (nonatomic)NSString *name;   
  • reter é necessário quando o atributo é um ponteiro para um objeto.

O método setter aumentará a contagem de retenção do objeto, para que ele ocupe memória no pool de liberação automática.

@property (retain)NSString *name;
  • copiar Se você usa cópia, não pode usar reter. O uso da instância de cópia da classe conterá sua própria cópia.

Mesmo que uma sequência mutável seja definida e alterada posteriormente, a instância captura qualquer valor que tiver no momento em que é definida. Nenhum método setter e getter será sintetizado.

@property (copy) NSString *name;

agora,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

O nome permanecerá inalterado.

  • readonly Se você não deseja permitir que a propriedade seja alterada pelo método setter, você pode declarar a propriedade somente leitura.

O compilador irá gerar um getter, mas não um setter.

@property (readonly) NSString *name;
  • readwrite é o comportamento padrão. Você não precisa especificar o atributo readwrite explicitamente.

É o oposto de somente leitura.

@property (readwrite) NSString *name;
  • assign gera um setter que atribui o valor diretamente à variável de instância, em vez de copiá-lo ou retê-lo. É melhor para tipos primitivos como NSInteger e CGFloat, ou objetos que você não possui diretamente, como delegados.

Lembre-se de que reter e atribuir são basicamente intercambiáveis ​​quando a coleta de lixo está ativada.

@property (assign) NSInteger year;
  • forte é um substituto para reter.

Ele vem com o ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Se você deseja usar um nome diferente para um método getter, é possível especificar um nome personalizado adicionando atributos à propriedade.

No caso de propriedades booleanas (propriedades que têm um valor SIM ou NÃO), é habitual que o método getter comece com a palavra "é"

@property (getter=isFinished) BOOL finished;
  • setter = method Se você deseja usar um nome diferente para um método setter, é possível especificar um nome personalizado adicionando atributos à propriedade.

O método deve terminar com dois pontos.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Existem algumas classes no Cocoa e no Cocoa Touch que ainda não suportam referências fracas, o que significa que você não pode declarar uma propriedade fraca ou uma variável local fraca para acompanhá-las. Essas classes incluem NSTextView, NSFont e NSColorSpace, etc. Se você precisar usar uma referência fraca para uma dessas classes, deverá usar uma referência não segura.

Uma referência insegura é semelhante a uma referência fraca, pois não mantém seu objeto relacionado ativo, mas não será definido como nulo se o objeto de destino for desalocado.

@property (unsafe_unretained) NSObject *unsafeProperty;

Se você precisar especificar vários atributos, basta incluí-los como uma lista separada por vírgula, assim:

@property (readonly, getter=isFinished) BOOL finished;
liza
fonte
Além disso, fraco significa que não há uma contagem de referência para o referenciado para o objeto, mas que ele é referenciado, ou não é referenciado. Mais ou menos como "sim, algo me referenciou" vs. "9 referências a mim existem" (que é como é forte).
Alex Zavatone
6
Ignore a linha na resposta referente à coleta de lixo, pois a coleta de lixo é preterida no Mac OS X e inexistente no iOS, conforme a documentação da Apple .
Basil Bourque
4
"Nota: Atomicidade de propriedade não é sinônimo de segurança de encadeamento de um objeto." - from developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7
1
"Se você declarar um objeto usando @propertyno arquivo de cabeçalho, precisará sintetizá-lo usando @synthesizeo arquivo de implementação." Nem sempre. Por exemplo, "Por padrão, uma readwritepropriedade será apoiada por uma variável de instância, que será novamente sintetizada automaticamente pelo compilador". Do doc .
Franklin Yu
4
@liza Esta é uma excelente resposta. Por que essa não é a resposta aceita? Ele transmite uma explicação muito mais experiente do que a resposta atualmente aceita. Eu não entendo StackOverflow às vezes?
Charles Robertson
149

Depois de ler muitos artigos, decidi reunir todas as informações de atributos:

  1. atomic // default
  2. não atômico
  3. strong = reter // padrão
  4. fraco = unsafe_unretained
  5. reter
  6. atribuir // padrão
  7. unsafe_unretained
  8. cópia de
  9. somente leitura
  10. readwrite // padrão

Abaixo está um link para o artigo detalhado, onde você pode encontrar esses atributos.

Muito obrigado a todas as pessoas que dão as melhores respostas aqui !!

Atributos de propriedade variável ou modificadores no iOS

Aqui está a descrição da amostra do artigo

  1. atomic -Atomic significa que apenas um thread acessa a variável (tipo estático). -Atômico é seguro para threads. -mas o desempenho é lento -atômico é o comportamento padrão -Os acessadores atômicos em um ambiente sem coleta de lixo (por exemplo, ao usar reter / liberar / liberação automática) usarão um bloqueio para garantir que outro encadeamento não interfira na configuração / obtenção correta do valor. -não é realmente uma palavra-chave.

Exemplo:

@property (retain) NSString *name;

@synthesize name;
  1. não-atômicas meios -Nonatomic acesso múltiplo segmento variável (tipo dinâmico). -Nonatômico é um segmento inseguro. -mas é rápido no desempenho -Nonatômico NÃO é um comportamento padrão, precisamos adicionar palavras-chave não-atômicas no atributo de propriedade. -pode resultar em comportamento inesperado, quando dois processos diferentes (threads) acessam a mesma variável ao mesmo tempo.

Exemplo:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Explicar:

Suponha que exista uma propriedade de string atômica chamada "name" e, se você chamar [self setName: @ "A"] do thread A, chame [self setName: @ "B"] do thread B e chame [self name] de thread C, todas as operações em threads diferentes serão executadas em série, o que significa que, se um thread estiver executando o setter ou getter, os outros threads aguardarão. Isso torna a propriedade "nome" de leitura / gravação segura, mas se outro encadeamento D chamar [release de nome] simultaneamente, essa operação poderá causar uma falha porque não há nenhuma chamada de setter / getter envolvida aqui. O que significa que um objeto é seguro para leitura / gravação (ATOMIC), mas não é seguro para threads, pois outros threads podem enviar simultaneamente qualquer tipo de mensagem para o objeto. O desenvolvedor deve garantir a segurança do encadeamento para esses objetos.

Se a propriedade "nome" não for atômica, todos os threads no exemplo acima - A, B, C e D serão executados simultaneamente, produzindo qualquer resultado imprevisível. No caso de atômico, um de A, B ou C será executado primeiro, mas D ainda pode ser executado em paralelo.

  1. strong (iOS4 = reter) - ele diz "mantenha isso na pilha até que eu não aponte mais" - em outras palavras "eu sou o proprietário, você não pode desalocar isso antes de procurar o mesmo que reter" - Você usa forte apenas se precisar reter o objeto. -Por padrão, todas as variáveis ​​de instância e variáveis ​​locais são fortes indicadores. -Nós geralmente usamos forte para UIViewControllers (pais do item de interface do usuário). O ARC o libera automaticamente para você quando terminar. Usar a palavra-chave strong significa que você é o proprietário do objeto.

Exemplo:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. fraco (iOS4 = unsafe_unretained) - ele diz "mantenha isso enquanto alguém apontar isso fortemente" - a mesma coisa que atribuir, sem reter ou liberar - uma referência "fraca" é uma referência que você não retém. Geralmente, usamos fraca para IBOutlets (Childs de UIViewController). Isso funciona porque o objeto filho só precisa existir enquanto o objeto pai existir. -uma referência fraca é uma referência que não protege o objeto referenciado da coleção por um coletor de lixo. -Weak é essencialmente atribuído, uma propriedade não retida. Exceto quando o objeto é desalocado, o ponteiro fraco é automaticamente definido como nulo

Exemplo:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Explicação forte e fraca, graças a BJ Homer :

Imagine que nosso objeto seja um cachorro e que ele queira fugir (ser desalocado). Ponteiros fortes são como uma trela no cachorro. Enquanto você tiver a trela presa ao cachorro, ele não fugirá. Se cinco pessoas prenderem a trela a um cachorro (cinco indicadores fortes para um objeto), o cão não fugirá até que todas as cinco trelas sejam separadas. Os indicadores fracos, por outro lado, são como crianças apontando para o cachorro e dizendo "Olha! Um cachorro!" Enquanto o cachorro ainda estiver na coleira, as crianças pequenas ainda poderão vê-lo e ainda apontarão para ele. Assim que todas as trelas são separadas, o cão foge, não importa quantas crianças pequenas estejam apontando para ele. Assim que o último ponteiro forte (trela) não apontar mais para um objeto, ele será desalocado e todos os ponteiros fracos serão zerados. Quando usamos fraco? O único momento em que você deseja usar fraco é se você deseja evitar reter ciclos (por exemplo, o pai retém o filho e o filho retém o pai, para que nunca seja liberado).

  1. reter = forte - é retido, o valor antigo é liberado e é atribuído - retém especifica que o novo valor deve ser enviado - retém na atribuição e o valor antigo enviado - liberta - retém é o mesmo que forte. -apple diz que se você escrever reter, ele será automaticamente convertido / funcionará apenas como forte. -métodos como "alocar" incluem um "reter" implícito

Exemplo:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. assign -assign é o padrão e simplesmente executa uma atribuição de variável -assign é um atributo de propriedade que informa ao compilador como sintetizar a implementação do setter da propriedade.

Exemplo:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained é um qualificador de propriedade que diz ao ARC como inserir chamadas de retenção / liberação -unsafe_unretained é a versão do ARC de assign.

Exemplo:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. copy -copy é necessário quando o objeto é mutável. -copy especifica que o novo valor deve ser enviado -copy na atribuição e o valor antigo enviado -release. -copy é como reter retorna um objeto que você deve liberar explicitamente (por exemplo, em desalocação) em ambientes sem coleta de lixo. -se você usar cópia, ainda precisará liberá-lo em desalocação. -Use isso se você precisar do valor do objeto como está neste momento e não desejar que esse valor reflita as alterações feitas por outros proprietários do objeto. Você precisará liberar o objeto quando tiver terminado porque está mantendo a cópia.

Exemplo:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
swiftBoy
fonte
2
Acho que depois do arco, reter não é mais usado.
mert
1
a lista completa perde dois itens de opção: setter e getter, que também são as únicas opções que precisam de argumento.
Scott Chu
forte ou reter é o padrão apenas para o tipo de objeto. Não pode ser usado para tipos primitivos.
Saleh Enam Shohag
9

A propriedade atômica pode ser acessada por apenas um encadeamento por vez. É thread-safe . O padrão é atômico. Observe que não há palavra-chave atômica

Não atômico significa que vários segmentos podem acessar o item. segmento inseguro

Portanto, deve-se ter muito cuidado ao usar atômica. Isso afeta o desempenho do seu código

Kannan Prasad
fonte
3
"Nota: Atomicidade de propriedade não é sinônimo de segurança de encadeamento de um objeto." A partir de developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7