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?


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.


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;

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

@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.



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 .


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.


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;


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.