ARC Objective-C: forte vs reter e fraco vs atribuir

367

Existem dois novos atributos de gerenciamento de memória para propriedades introduzidas pelo ARC stronge weak.

Além de copy, o que obviamente é algo completamente diferente, existem diferenças entre strongvs retaine weakvs assign?

Pelo meu entendimento, a única diferença aqui é que weakserá atribuída nilao ponteiro, enquanto assignnão será, o que significa que o programa falhará quando eu enviar uma mensagem ao ponteiro depois que ele for lançado. Mas se eu usar weak, isso nunca acontecerá, porque o envio de mensagens para nilnão fará nada.

Eu não sei sobre nenhuma diferença entre stronge retain.

Existe alguma razão pela qual devo usar assigne retainem novos projetos ou o tipo de depreciação?

Jakub Arnold
fonte
12
Há três novos atributos de gerenciamento de memória para propriedades introduzidas pela ARC strong, weake unsafe_unretained.
Jones19 de
5
@NJones Existem dois atributos de propriedade ( weake strong) e 4 qualificadores vida variáveis ( __strong, __weak, __unsafe_unretained, __autoreleasing). Veja as notas do ARC abaixo.
Snowcrash
11
@SnowCrash Havia uma versão do Xcode, provavelmente uma prévia do desenvolvedor, na qual o uso assignao compilar com o ARC era um erro. Existem muitas respostas excluídas sobre isso. Parece que foi alterado antes do lançamento final. unsafe_unretainedé o atributo preferido para muitos de nós que adotamos cedo. Para provar que unsafe_unretainedé um atributo válido, consulte "Programação com objetivo-C" da Apple, na seção "Encapsulando dados", na sub-rubrica "Use referências não seguras e não retidas para algumas classes". O que diz: "Para uma propriedade, isso significa usar o atributo unsafe_unretained:"
NJones 20/02/2013

Respostas:

230

Das notas de versão Transição para ARC (o exemplo na seção sobre atributos de propriedade).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Assim strongé o mesmo que retainem uma declaração de propriedade.

Para projetos ARC que eu usaria em strongvez de retain, usaria assignpara propriedades primitivas C e weakpara referências fracas a objetos Objective-C.

JeremyP
fonte
11
De fato, no ARC, é um erro de compilação a ser usado assignpara um objeto. Você precisa usar um weakou unsafe_unretained(o que é inseguro, obviamente) se não quiser reter a propriedade.
cobbal
5
assigncompila muito bem para mim em projetos ARC com o destino de implantação 4.0.
Pascal
8
@ Pascal: referências fracas não são permitidas em destinos de implantação em que o sistema operacional não é 5.0 ou superior. Assim, para projetos mais antigos, você ainda pode usar atribuir, mas se você mover para versões mais recentes que você tem a chave para o nível fraco
Mattia
11
Aparência como Xcode 4 (com ARC) gera NSManagedObject subclasses usando retainvs strong. Suponho que isso seja inofensivo, mas imagino que seja strongpor consistência ... ou talvez não importe. stackoverflow.com/questions/7796476/…
Joe D'Andrea
3
@ JeremyP Sim, sua resposta é imediata. Eu estava reagindo à @Mattia. Eu estava apontando que assignainda é válido em alguns casos.
9303 Steven Oxley
606

Depois de ler tantos artigos, publicações do Stackoverflow e aplicativos de demonstração para verificar atributos de propriedades variáveis, decidi reunir todas as informações de atributos:

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

Abaixo está o link detalhado do artigo, onde você pode encontrar todos os atributos mencionados acima, que definitivamente o ajudarão. Muito obrigado a todas as pessoas que dão as melhores respostas aqui !!

Atributos de propriedade variável ou modificadores no iOS

1. forte (iOS4 = reter)

  • diz "mantenha isso na pilha até que eu não aponte mais"
  • em outras palavras, "eu sou o proprietário, você não pode desassociar isso antes de apontar bem com 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.
  • Geralmente usamos forte para UIViewControllers (pais do item de interface do usuário)
  • strong é usado com o ARC e basicamente ajuda você, não precisando se preocupar com a contagem de retenções de um objeto. 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;

2.weak -

  • 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 (UIViewControllerer's Childs). 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.
  • Fraco é 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 cão (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ê gostaria de usar fraco é se você queria evitar manter ciclos (por exemplo, o pai retém o filho e o filho retém o pai, para que nunca seja liberado).

3. reter = forte

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

Exemplo:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4. atribuir

  • 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
  • Eu usaria assign para propriedades primitivas C e fraco para referências fracas a objetos Objective-C.

Exemplo:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
fonte
5
2. "uma referência fraca é uma referência que não protege o objeto referenciado da coleta por um coletor de lixo" - não existe no objetivo c como coletor de lixo;
22415
11
e essa hierarquia é gerenciada pelo iOS automaticamente. Leia sobre o conceito MVC. Quero dizer, quando o ViewContorller está sendo apresentado, o iOS carrega sua hierarquia de visualizações na tela (criando visualizações ausentes). Quando outro ViewController é apresentado, essa primeira hierarquia de visualizações é desalocada. Mas se você tiver 'forte' no ViewController, essa visualização não poderá ser desalocada quando estiver fora da tela. O que pode ter um forte impacto na memória do dispositivo e causar lentidão no aplicativo. (Of dispositivo curso tem um monte de memória e você definitivamente ficar bem em 5-10 aplicativo tela, mas no aplicativo enorme você vai entrar em apuros)
bucherland
11
Quando usamos fraco? 1. Para UI objetos, 2. delegados, 3. blocos (weakSelf deve ser usado em vez de si a ciclos de memória evitar (como foi mencionado acima)
bucherland
11
Há um erro nesta ótima resposta - forte - "O ARC o libera automaticamente quando você termina", isso não está certo. O ARC liberará automaticamente objetos fracos quando não houver ponteiros para eles. Forte - é sinônimo de retenção, portanto o objeto é retido e é nossa responsabilidade tornar o objeto nulo.
Ashwin G
11
@RDC, o que defaultsignifica? Se eu usar @property (nonatomic) NSString *stringé strong? Ou assign? Porque ambos são padrões.
Iulian Onofrei
40

não atômico / atômico

  • não atômico é muito mais rápido que atômico
  • sempre use não atômico, a menos que você tenha um requisito muito específico para atômico, o que deve ser raro (o atômico não garante a segurança do encadeamento - apenas interrompe o acesso à propriedade quando ele é definido simultaneamente por outro encadeamento)

forte / fraco / atribuir

  • use forte para reter objetos - embora a palavra-chave retenha seja sinônimo, é melhor usar forte
  • use fraco se você quiser apenas um ponteiro para o objeto sem retê-lo - útil para evitar ciclos de retenção (por exemplo, delegados) - ele automaticamente apagará o ponteiro quando o objeto for liberado
  • use assign para primitivos - exatamente como fraco, exceto que o objeto não é nulo quando liberado (definido por padrão)

(Opcional)

cópia de

  • use-o para criar uma cópia superficial do objeto
  • boa prática para sempre definir propriedades imutáveis ​​para copiar - como versões mutáveis ​​podem ser passadas para propriedades imutáveis, a cópia garantirá que você sempre lide com um objeto imutável
  • se um objeto imutável for passado, ele será retido - se um objeto mutável for passado, ele será copiado

somente leitura

  • use-o para desativar a configuração da propriedade (impede a compilação do código se houver uma infração)
  • você pode alterar o que é entregue pelo getter alterando a variável diretamente por meio da variável de instância ou dentro do próprio método getter
Vadoff
fonte
@Sakthimuthiah está certo, você deve corrigir sua resposta.
21416 Adela Toderici
@Sakthimuthiah está incorreto (e qualquer outra pessoa que diz isso). O Atomic NÃO o torna seguro para threads, embora possa ser facilmente confundido devido ao seu comportamento. Leia: stackoverflow.com/questions/12347236/…
Chris J
39

Tanto quanto eu sei, stronge retainsão sinônimos, então eles fazem exatamente o mesmo.

Então, weaké quase como assign, mas automaticamente definido como nulo, depois que o objeto, para o qual está apontando, é desalocado.

Isso significa que você pode simplesmente substituí-los.

No entanto , há um caso especial que encontrei, onde tive que usar assign, e não weak. Digamos que temos duas propriedades delegateAssigne delegateWeak. Nos dois está armazenado nosso delegado, que está nos possuindo por ter a única referência forte. O delegado está desalocando, então nosso -deallocmétodo também é chamado.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

O delegado já está em processo de desalocação, mas ainda não está totalmente desalocado. O problema é que as weakreferências a ele já estão anuladas! A propriedade delegateWeakcontém nulo, mas delegateAssigncontém um objeto válido (com todas as propriedades já liberadas e anuladas, mas ainda válidas).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

É um caso bastante especial, mas nos revela como essas weakvariáveis ​​funcionam e quando são anuladas.

Tricertops
fonte
20

Documento de Clang sobre a contagem automática de referência Objective-C (ARC) explica claramente os qualificadores e modificadores de propriedade:

Existem quatro qualificadores de propriedade:

  • __ autoreleasing
  • __ forte
  • __ * unsafe_unretained *
  • __ fraco

Um tipo é qualificado de propriedade de maneira não trivial se estiver qualificado com __ autoreleasing , __ forte ou __ fraco .

Existem seis modificadores de propriedade para a propriedade declarada:

  • atribuir implica em __ * propriedade não segura *.
  • cópia implica __ propriedade forte , bem como o comportamento usual da semântica de cópia no setter.
  • reter implica __ propriedade forte .
  • forte implica __ propriedade forte .
  • * unsafe_unretained * implica __ * unsafe_unretained * propriedade.
  • fraco implica __ propriedade fraca .

Com exceção de fraco , esses modificadores estão disponíveis nos modos não-ARC.

Em termos semânticos, os qualificadores de propriedade têm um significado diferente nas cinco operações gerenciadas : Leitura, Designação, Inicialização, Destruição e Movimentação, nas quais na maioria das vezes nos preocupamos apenas com a diferença na operação de Designação.

A atribuição ocorre ao avaliar um operador de atribuição. A semântica varia de acordo com a qualificação:

  • Para __ forte objetos , o novo ponta é retido primeiro; segundo, o lvalue é carregado com semântica primitiva; terceiro, o novo ponta é armazenado no valor com semântica primitiva; e finalmente, o velho pointee é libertado. Isso não é realizado atomicamente; a sincronização externa deve ser usada para tornar isso seguro diante de cargas e armazenamentos simultâneos.
  • Para __ objetos fracos , o lvalue é atualizado para apontar para o novo ponta, a menos que o novo ponta seja um objeto atualmente em desalocação, nesse caso o lvalue é atualizado para um ponteiro nulo. Isso deve ser executado atomicamente em relação a outras atribuições ao objeto, às leituras do objeto e à liberação final do novo apontador.
  • Para objetos __ * unsafe_unretained *, o novo ponta é armazenado no lvalue usando semântica primitiva.
  • Para __ autoreleasing objectos, o novo pointee é retida, autoreleased, e armazenado na Ivalue usando semântica primitivas.

A outra diferença em Leitura, Inicialização, Destruição e Movimentação, consulte a Seção 4.2 Semântica no documento .

Mingming
fonte
6

Para entender as referências Forte e Fraca, considere o exemplo abaixo, suponha que tenhamos o método nomeado como displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

No método acima, o escopo da variável myName é limitado ao método displayLocalVariable, assim que o método for concluído, a variável myName, que contém a string "ABC", será desalocada da memória.

Agora, e se quisermos manter o valor da variável myName durante todo o ciclo de vida do controlador de exibição. Para isso, podemos criar a propriedade nomeada como nome de usuário, que terá forte referência à variável myName (veja o self.username = myName;código abaixo), como abaixo,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Agora, no código acima, você pode ver que myName foi atribuído a self.username e self.username está tendo uma forte referência (como declaramos na interface usando @property) a myName (indiretamente, está tendo forte referência à cadeia "ABC"). Portanto, String myName não será desalocada da memória até que self.username esteja ativo.

  • Referência fraca

Agora considere atribuir myName a dummyName, que é uma referência fraca, self.dummyName = myName; Diferentemente da referência Forte, Fraco manterá o meuNome apenas até que haja uma referência Forte ao meuNome. Veja o código abaixo para entender a referência fraca,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

No código acima, há uma referência fraca a meu nome (ou seja, self.dummyName está com uma referência fraca a meu nome), mas não há uma referência forte a meu nome, portanto, self.dummyName não poderá manter o valor de meu nome.

Agora, considere novamente o código abaixo,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

No código acima, self.username possui uma forte referência a myName; portanto, self.dummyName agora terá um valor de myName mesmo depois que o método termina, já que myName tem uma referência forte associada a ele.

Agora, sempre que fizermos uma referência Forte a uma variável, a contagem de retenções será aumentada em um e a variável não será desalocada.

Espero que isto ajude.

Mahadev Mandale
fonte
2

Forte:

  • A propriedade não será destruída, mas somente quando você definir a propriedade para zero, o objeto será destruído
  • Por padrão, todas as variáveis ​​de instância e variáveis ​​locais são fortes indicadores.
  • Você usa forte apenas se precisar reter o objeto.
  • Geralmente usamos forte para UIViewControllers (pais do item de interface do usuário)
  • IOS 4 (não-ARC) que podemos usar Reter KeyWord
  • IOS 5 (ARC), podemos usar palavras-chave fortes

Exemplo: @property (forte, não atômico) ViewController * viewController;

@synthesize viewController;

Fraco

Por padrão, obtém e define automaticamente como nulo

  • Geralmente usamos fraco para IBOutlets (UIViewControllerer's Childs) e delegamos
  • a mesma coisa que atribuir, sem reter ou liberar

Exemplo: @property (fraco, não atômico) IBOutlet UIButton * myButton;

@synthesize myButton;

Nikunj Patel
fonte
1

As diferenças entre forte e reter:

  • No iOS4, forte é igual para reter
  • Isso significa que você é o proprietário do objeto e o mantém na pilha até que não aponte mais para ele
  • Se você escrever reter, ele funcionará automaticamente como forte

As diferenças entre fraco e atribuir:

  • Uma referência "fraca" é uma referência que você não retém e a mantém desde que alguém a aponte fortemente
  • Quando o objeto é "desalocado", o ponteiro fraco é automaticamente definido como nulo
  • Um atributo de propriedade "assign" informa ao compilador como sintetizar a implementação do setter da propriedade
Chen Rui
fonte