Como substituo referências fracas ao usar o ARC e direcionar o iOS 4.0?

87

Comecei a desenvolver meu primeiro aplicativo iOS com o Xcode 4.2 e estava visando o iOS 5.0 com um modelo de "aplicativo utilitário" (o que vem com um FlipsideViewController).

Eu li que, como ARC é um recurso de tempo de compilação, ele também deve ser compatível com o iOS 4, então tentei direcionar meu aplicativo para 4.3 e tentar compilá-lo. Ao fazer isso, recebo este erro:

FlipsideViewController.m: erro: Contagem automática de referência Problema: O destino de implantação atual não oferece suporte a referências __weak automatizadas

Está referenciando esta linha:

@synthesize delegate = _delegate;

Essa variável é declarada como:

@property (weak, nonatomic) IBOutlet id <FlipsideViewControllerDelegate> delegate;

Eu entendo que "referências fracas" não são suportadas no iOS 4, mas eu realmente não entendo porque eu gostaria de usar uma referência fraca para começar, nem consigo descobrir como eu iria reescrever as coisas para evitar usá-la, enquanto ainda aproveitando o ARC (afinal, ele deve funcionar com iOS 4 e 5, certo?)

Mason G. Zhwiti
fonte

Respostas:

149

Para direcionar o sistema operacional mais antigo, você pode usar em unsafe_unretainedvez de weakem sua declaração de propriedade, e geralmente deve funcionar da mesma maneira. weakas referências anulam-se quando seu destino desaparece, mas unsafe_unretaineddeixa em aberto a possibilidade de que o objeto ao qual você está vinculando possa se transformar em um ponteiro pendente quando for desalocado. O último é o mesmo comportamento como se você tivesse usado assigncomo uma declaração de propriedade no gerenciamento manual de memória.

Você faz isso para evitar reter ciclos, que menciono na minha resposta aqui . Você não quer ter um ponteiro forte para algo que pode ter um ponteiro forte de volta para o objeto original. Então, nada seria lançado corretamente.

Brad Larson
fonte
Obrigado pelo conselho. Você diz "para visar o sistema operacional mais antigo ...". Isso significa que só devo usar unsafe_unretained em compilações do aplicativo anteriores a 5.0? Ou posso apenas usar unsafe_unretained em meu código e compilá-lo para atingir 4.xe 5.x?
Mason G. Zhwiti
1
@Mason - unsafe_unretainedé compatível com iOS 4.xe 5.0, portanto, oferece compatibilidade com versões anteriores. Se você estiver fazendo uma compilação apenas 5.0, poderá alternar para weakpara aproveitar a segurança adicional que ele oferece.
Brad Larson
Eu tentei unsafe_unretained, funcionou de qualquer maneira. No entanto, recebi muitos avisos como '"** __NSAutoreleaseNoPool (): Objeto 0x564bd90 da classe __NSArrayM liberado automaticamente sem pool no local - apenas vazando" *', isso é normal?
quinto dia
1
@ quinto - Esse é um problema totalmente não relacionado. Você está executando algo em um thread de segundo plano sem ter um pool de liberação automática no lugar. Threads criados manualmente não têm seu próprio pool de autorelease, então você precisa criar um usando @autoreleasepool(em ARC, NSAutoreleasePool para implementações contadas de referência manual mais antigas).
Brad Larson
@Brad, isso é útil, os avisos sumiram, recebi várias chamadas performSelectorInBackground.
quinto dia
11

Se estiver usando apenas referências fracas para segurança adicional, chame manualmente as novas funções de tempo de execução se estiverem disponíveis e retorne para atribuição simples em __unsafe_unretainedvariáveis, caso não estejam .

ZWRCompatibility.h irá simplificar isso um pouco.

Rpetrich
fonte
10

Graças à biblioteca de compatibilidade PLWeakCompatibilty de Mike Ash , agora você também pode usar __weak no iOS 4.x.

É incrivelmente fácil de configurar e não requer nenhuma consideração ou esforço adicional em relação ao 5.x.

nschum
fonte