Para ARC ou não para ARC? Quais são os prós e contras? [fechadas]

113

Ainda não usei o ARC, já que a maioria do código do projeto em que estou trabalhando no momento foi escrito antes do iOS 5.0.

Eu estava me perguntando: a conveniência de não reter / liberar manualmente (e, presumivelmente, um código mais confiável que vem como resultado?) Supera qualquer 'custo' de usar o ARC? Quais são suas experiências com o ARC e você o recomendaria?

Assim:

  • Qual é o benefício que o ARC pode trazer para um projeto?
  • O ARC tem um custo como a coleta de lixo em Java?
  • Você tem usado o ARC e, em caso afirmativo, como o encontrou até agora?
Simon Withington
fonte
Não há coleta de lixo no ipad / ios. Você está falando sobre o OS X?
dasblinkenlight
1
Minhas desculpas, estou usando termos Java fora do lugar. Quero dizer que, com o ARC, os objetos podem ser mantidos na memória por mais tempo do que o necessário e, em seguida, liberados como um grupo em um pool de liberação automática algum tempo depois. É esse efeito de serem mantidos e liberados com outros objetos posteriormente, de forma semelhante à coleta de lixo do Java a que estou me referindo.
Simon Withington
3
@TenementFunster, para o mesmo código (sem as chamadas para liberação), o ARC não manterá o objeto por mais tempo do que o código não ARC. Na verdade, muitas vezes ele o lançará mais cedo do que você. Há um pequeno número de coisas que são um pouco mais lentas, mas aceleram tanto os padrões comuns que diminuem o impacto no desempenho. Para muitos padrões comuns (reter um objeto que foi retornado com um autorelease, por exemplo), você literalmente não pode escrever à mão tão rápido quanto o ARC o faria automaticamente.
Rob Napier
1
Com relação à coleta de lixo, veja minha resposta a esta pergunta semelhante: Qual é a diferença entre contagem automática de referência Objective-C e coleta de lixo?
Brad Larson

Respostas:

147

Não há nenhuma desvantagem. Use-o. Faça hoje. É mais rápido que seu código antigo. É mais seguro do que seu código antigo. É mais fácil do que seu código antigo. Não é coleta de lixo. Não tem sobrecarga de tempo de execução do GC. O compilador insere retém e libera em todos os lugares que você deveria ter de qualquer maneira. Mas é mais inteligente do que você e pode otimizar aqueles que não são realmente necessários (assim como pode desfazer loops, eliminar variáveis ​​temporárias, funções embutidas, etc.)

OK, agora vou falar sobre as pequenas desvantagens:

  • Se você é um desenvolvedor de ObjC de longa data, ficará nervoso por cerca de uma semana ao ver o código ARC. Você vai superar isso muito rapidamente.

  • Existem algumas complicações (muito) pequenas na ponte para o código do Core Foundation. Existem um pouco mais de complicações em lidar com qualquer coisa que trate um idcomo um void*. Coisas como C-arrays de idpodem levar um pouco mais de reflexão para serem feitas corretamente. Manipulação extravagante de ObjC va_argstambém pode causar problemas. A maioria das coisas que envolvem matemática em um ponteiro ObjC é mais complicada. Você não deve ter muito disso em qualquer caso.

  • Você não pode colocar um idem a struct. Isso é bastante raro, mas às vezes é usado para empacotar dados.

  • Se você não seguiu a nomenclatura KVC correta e misturou código ARC e não ARC, terá problemas de memória. ARC usa nomenclatura KVC para tomar decisões sobre o gerenciamento de memória. Se for todo código ARC, então não importa porque fará o mesmo "errado" em ambos os lados. Mas se for misto ARC / não ARC, então há uma incompatibilidade.

  • ARC vazará memória durante lançamentos de exceção ObjC. Uma exceção ObjC deve estar muito próxima ao encerramento do seu programa. Se você está detectando um número significativo de exceções ObjC, está usando-as incorretamente. Isso pode ser corrigido usando -fobjc-arc-exceptions, mas incorre nas penalidades discutidas abaixo:

  • O ARC não vazará memória durante o lançamento de exceções ObjC ou C ++ no código ObjC ++, mas isso prejudica o desempenho de tempo e espaço. Esta é mais uma em uma longa lista de razões para minimizar o uso de ObjC ++.

  • ARC não funcionará em iPhoneOS 3 ou Mac OS X 10.5 ou anterior. (Isso me impede de usar o ARC em muitos projetos.)

  • __weakos ponteiros não funcionam corretamente no iOS 4 ou Mac OS X 10.6, o que é uma pena, mas bastante fácil de contornar. __weakas dicas são ótimas, mas não são o ponto de venda nº 1 da ARC.

Para mais de 95% do código, o ARC é brilhante e não há razão para evitá-lo (desde que você possa lidar com as restrições de versão do sistema operacional). Para código não ARC, você pode passar -fno-objc-arcarquivo por arquivo. Infelizmente, o Xcode torna isso muito mais difícil do que deveria ser na prática. Você provavelmente deve mover o código não ARC para um xcodeproj separado para simplificar isso.

Em conclusão, mude para o ARC assim que puder e nunca olhe para trás.


EDITAR

Já vi alguns comentários do tipo "usar o ARC não substitui o conhecimento das regras de gerenciamento de memória Cocoa". Isso é verdade, mas é importante entender por que e por que não. Primeiro, se todo o seu código usar ARC e você violar as Três Palavras Mágicasem todo o lugar, você ainda não terá problemas. Chocante dizer, mas aí está. O ARC pode reter algumas coisas que você não pretendia reter, mas também as liberará, portanto, isso nunca terá importância. Se eu fosse dar uma nova aula em Cocoa hoje, provavelmente não gastaria mais do que cinco minutos nas regras reais de gerenciamento de memória e provavelmente apenas mencionaria as regras de nomenclatura de gerenciamento de memória ao discutir a nomenclatura KVC. Com o ARC, acredito que você poderia realmente se tornar um programador iniciante decente sem aprender as regras de gerenciamento de memória.

Mas você não poderia se tornar um programador intermediário decente. Você precisa conhecer as regras para fazer a ponte corretamente com o Core Foundation, e todo programador intermediário precisa lidar com o CF em algum ponto. E você precisa conhecer as regras para código ARC / MRC misto. E você precisa conhecer as regras quando começar a mexer com void*ponteiros para id(que você continua a precisar para executar KVO corretamente). E blocos ... bem, o gerenciamento de memória em bloco é simplesmente estranho.

Portanto, meu ponto é que o gerenciamento de memória subjacente ainda é importante, mas onde eu costumava gastar um tempo significativo declarando e reafirmando as regras para novos programadores, com o ARC ele está se tornando um tópico mais avançado. Prefiro fazer com que os novos desenvolvedores pensem em termos de gráficos de objetos em vez de preencher suas cabeças com as chamadas subjacentes para objc_retain().

Rob Napier
fonte
3
Uma coisa para ter muito cuidado (em não-ARC também, mas ainda mais em ARC porque é tão invisível agora) é reter os ciclos. Meu conselho aqui é 1) se você estiver armazenando um bloco objc como uma variável de instância, dê uma boa olhada nele para ver se ele poderia capturar o objeto do qual é um ivar, mesmo que indiretamente. 2) Projete realmente seu gráfico de objetos, ao invés de apenas deixar acontecer. Você deve saber o que possui e se quiser escrever um bom código. 3) Use heapshots: friday.com/bbum/2010/10/17/…
Catfish_Man
1
@Catfish_Man Todos os pontos positivos. Reter loops sempre foi um problema. O novo conselho da Apple é exatamente o que você disse no nº 2. Precisamos pensar em gráficos de objetos em vez de retê-los e liberá-los. # 1 é um problema sério com bloqueios e uma das várias razões pelas quais considero os bloqueios uma bênção mista que deve ser abordada com cautela.
Rob Napier
2
Há uma desvantagem séria que não foi mencionada: compatibilidade cruzada. Para nós, almas corajosas e tolas que enfrentamos as terras devastadas conhecidas como programação multiplataforma, ARC simplesmente não é uma opção, pelo menos não até que o GNU expanda seu tempo de execução ObjC e recursos de compilador novamente (eles dizem que mais está a caminho).
Coelho
2
Você pode usar o ARC, exceto que precisa oferecer suporte a dispositivos iOS 3.x. BTW, certifique-se de usar o Xcode para fazer a transição (Edit> Refactor> Convert to Objective-C ARC). Durante o processo, o Xcode faria muitas validações para garantir que seu código funcionaria e descobriria quaisquer códigos que violassem essas diretrizes de design.
ZhangChn
1
Excelente .. responda pontualmente. isso é 100º de mim. Parabéns por um século;)
Ajay Sharma
20

Melhor, respostas mais técnicas do que as minhas virão, mas aqui vai:

  • ARC! = Coleta de lixo. Não há penalidade de tempo de execução, isso é feito em tempo de compilação.
  • ARC também! = Apenas liberando tudo automaticamente, como você sugere em seu comentário. Leia a documentação
  • É incrível quando você percebe quanto gerenciamento de referência manual estava fazendo
  • Use-o!
  • Uma desvantagem - manter o código antigo, diferente do arco, de repente se torna muito tedioso.
Jrturton
fonte
Sim, é por isso que não o usei até agora - não tenho certeza se aguentaria passar por nossa quantidade substancial de código pré-existente para convertê-lo ... Definitivamente vou tentar no próximo projeto. Obrigado pela sua resposta :)
Simon Withington
Não é que manter o código antigo se torne mais difícil, é que sua expectativa mudou. Portanto, não é realmente justo culpar a ARC por tornar a vida mais fácil. O Xcode facilita a conversão de seu código antigo em ARC quando estiver pronto, mas obviamente você não pode usá-lo se ainda precisar oferecer suporte a versões mais antigas do iOS.
Caleb
1
@Caleb Eu não estava culpando o ARC, é apenas essa a única desvantagem que vi até agora - me estragou muito no espaço de um único projeto.
jrturton
Sim; Eu não listei isso como um problema, mas há um pequeno problema de sair da prática de gerenciamento de memória quando você precisa alternar entre as bases de código. Alguns de meus projetos rodam em 10.4, então eu ainda faço muito trabalho em Objective-C 1.0 (então nada de @synthesize, muito menos ARC). Mas você se acostuma muito bem a alternar entre os modos.
Rob Napier
@jrturton Eu deveria ter deixado mais claro que escrevi isso para o benefício do OP e dos futuros leitores que podem não grocar o que o ARC faz. Eu sei exatamente o que você quer dizer, só não queria que ninguém chegasse à conclusão errada de que misturar código ARC e não-ARC cria um problema.
Caleb
16

Qual é o benefício que o ARC pode trazer para um projeto?

O benefício é um grau significativo de proteção contra erros comuns de gerenciamento de memória. Vazamentos causados ​​por falha na liberação de um objeto e travamentos devido à falha em reter ou liberação prematura de um objeto devem ser significativamente reduzidos. Você ainda precisa entender o modelo de memória contada por referência para que possa classificar suas referências como fortes ou fracas, evitar ciclos de retenção e assim por diante.

Quanto a coleta de lixo realmente 'custa'?

Não há coleta de lixo no iOS. ARC é semelhante ao GC no sentido de que você não precisa reter ou liberar objetos manualmente. É diferente do GC porque não há coletor de lixo. O modelo de retenção / liberação ainda se aplica, é só que o compilador insere as chamadas de gerenciamento de memória apropriadas em seu código para você no momento da compilação.

Você tem usado o ARC e, em caso afirmativo, como o encontrou até agora?

É um pouco desconcertante se você está acostumado com a contagem de referências, mas é só uma questão de se acostumar e aprender a confiar que o compilador realmente fará a coisa certa. Parece uma continuação da mudança nas propriedades que veio com Objective-C 2.0, que foi outro grande passo em direção à simplificação do gerenciamento de memória. Sem as chamadas manuais de gerenciamento de memória, seu código se torna um pouco mais curto e fácil de ler.

O único problema com o ARC é que ele não é compatível com versões mais antigas do iOS, então você precisa levar isso em consideração antes de decidir adotá-lo.

Caleb
fonte
1
Essa é a melhor resposta de que eu estava falando!
jrturton
1
Sim, ótima resposta. Portanto, não há realmente nenhuma desvantagem para o ARC além de ter que aprender a confiar que ele funciona? Parece bom demais para ser verdade nesse caso?
Simon Withington
4

Acho que o ARC é uma ótima ideia. Comparado ao GC, você pode ter seu bolo e comê-lo. Eu tendo a acreditar que o MRC impõe uma 'disciplina' inestimável para o gerenciamento de memória que todos se beneficiariam em ter. Mas também concordo que a verdadeira questão a ter em conta é a propriedade do objeto e os gráficos de objeto (como muitos apontaram), e não as contagens de referência de baixo nível per se.

Para concluir: ARC NÃO é um passe livre para deixar de lado a memória; é uma ferramenta para ajudar o homem a evitar tarefas repetitivas, que causam estresse e estão sujeitas a erros, portanto, melhor delegadas a uma máquina (o compilador, neste caso).

Dito isso, pessoalmente sou um artesão e ainda não fiz a transição. Acabei de começar a usar o Git ...

ATUALIZAÇÃO: Portanto, migrei todo o meu jogo, incluindo a biblioteca gl, e sem problemas até agora (exceto com o assistente de migração no Xcode 4.2). Se você está começando um novo projeto, vá em frente.

Nicolas Miari
fonte
2

Eu o usei em alguns projetos (reconhecidamente pequenos) e só tenho boas experiências, tanto em desempenho quanto em confiabilidade.

Uma pequena nota de cautela é que você precisa aprender a fazer: se não: s de referências fracas para não causar nenhum loop de referência se você estiver codificando sua IU sozinho, o designer tende a fazer um bom trabalho automaticamente se você configurar sua GUI usando-o.

Joachim Isaksson
fonte
2

A única desvantagem que encontrei é se você usa uma biblioteca com muitas funções e dados CoreFoundation. No MRC, você não precisa se preocupar em usar um em CFStringRefvez de um NSString*. No ARC, você deve especificar como os dois interagem (ponte básica? Liberar o objeto CoreFoundation e movê-lo para ARC? Fazer um objeto Cocoa como um objeto retido CoreFoundation +1?) Além disso, no OS X, está disponível apenas no 64- código de bits (embora eu tenha um cabeçalho que contorna isso ...).

MaddTheSane
fonte