Uso de init init em vez de novo

344

Aprendendo o Objective-C e lendo o código de amostra, percebo que os objetos geralmente são criados usando este método:

SomeObject *myObject = [[SomeObject alloc] init];

ao invés de:

SomeObject *myObject = [SomeObject new];

Existe uma razão para isso, como eu li que eles são equivalentes?

willc2
fonte
12
Eu nem sabia que isso era possível! Todo o material que li finge que a nova palavra-chave não existe!
Jonathan
78
Na verdade, "new" não é uma palavra-chave no Objective-C, mas o NSObject implementa um método de classe "new" que simplesmente chama de "assign" e "init".
9789 Don McCaughey
3
Jonathan, foi exatamente isso que levou minha pergunta. Eles podem ser funcionalmente equivalentes, mas [[aloc] init] é claramente o idioma dominante.
willc2
11
Acho que a Apple (pelo que me lembro de uma de suas palestras do iTunes Stanford) apenas o incentiva a usar o init init para que você possa entender o processo do que está acontecendo. Eles também não usam muito novo em seu código de amostra, portanto, o init init parece ser apenas um bom hábito geral que a Apple tenta promover.
PostCodeism

Respostas:

290

Há várias razões aqui: http://macresearch.org/difference-between-alloc-init-and-new

Alguns selecionados são:

  • newnão suporta inicializadores personalizados (como initWithString)
  • alloc-init é mais explícito que new

A opinião geral parece ser que você deve usar o que quer que seja que seja confortável.

Jeremy Stanley
fonte
8
Se sua classe usar -init como inicializador designado, + new a chamará. O que Jeremy está se referindo é se você tiver um inicializador personalizado que não seja -init. -initWithName :, por exemplo.
21/09/09
87
Não há nada que o impeça de implementar +newWithString:também, se você já o implementou -initWithString. Não é tão comum assim. Pessoalmente, eu sempre uso newquando o inicializador designado é inittão curto e agradável.
PeyloW 21/09/09
11
Sei que esse é um tópico antigo, mas quero enfatizar que você não deve implementar +newWithString:. Isso quebra a separação de preocupações. Pois quando você só quer usar de -initqualquer maneira, não há motivo para não usar +new, no entanto.
Jonathan Sterling
7
@ JonathanSterling: A Apple tem muitos casos em que parece estar fazendo exatamente o que você aconselha; por exemplo, [[NSString alloc] initWithFormat:...]e [NSString stringWithFormat:...]são ambos equivalentes. Você está dizendo que a Apple violou a separação de preocupações e não deveria ter implementado dessa maneira? (Nota: Eu não estou tentando ser condescendente, eu gostaria apenas de obter mais informação e saber se seguindo o exemplo da Apple às vezes é uma má idéia.)
Senseful
6
@Senseful Eu acredito que remonta aos dias anteriores ao ARC (ou coleta de lixo). Essas duas coisas não somos equivalentes. stringWithFormat: retornaria uma string autoreleased enquanto o assign: init: precisaria ser liberado ou liberado manualmente, ou isso causaria um vazamento de memória.
Msfeldstein
139

Pergunta muito antiga, mas escrevi alguns exemplos apenas por diversão - talvez você ache útil;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

+(id)alloc{
    NSLog(@"Allocating...");
    return [super alloc];
}

-(id)init{
    NSLog(@"Initializing...");
    return [super init];
}

@end

Na função principal, ambas as instruções:

[[InitAllocNewTest alloc] init];

e

[InitAllocNewTest new];

resultam na mesma saída:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...
guitar_freak
fonte
5
Excelente resposta! Só quero acrescentar que usando + nova é ótimo para os casos em que você só precisa usar -init e nada mais especializada como -initWithSomething: ...
cgossain
Infelizmente, este exemplo não prova que eles são idênticos. É apenas um exemplo em que eles produzem o mesmo resultado.
Vince O'Sullivan
10
Infelizmente, este exemplo não prova que eles são idênticos. É apenas um exemplo em que elas produzem o mesmo resultado. Por outro lado, isso prova que são diferentes ... Tomando o exemplo acima, modifique "InitAllocNewTest.h" da seguinte maneira: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; O @end [[InitAllocNewTest alloc] init]não será compilado enquanto [InitAllocNewTest new]não for afetado. (Apologias para falta de quebras de linha, etc.)
Vince O'Sullivan
11
@ VinceO'Sullivan, bom ponto. Isso significa que, se alguém deseja tornar o init indisponível, como em uma classe singleton, deve-se desativar o novo também. Não vou falar aqui se singletons são bons ou ruins.
user3099609
Eu tenho uma pergunta do código acima. por que "return [super init];"? geralmente init é um método em que os membros da classe são inicializados, por que o ponteiro muda é muito estranho!
Pruthvidhar Rao Nadunooru
52

+newé equivalente +alloc/-initna NSObjectimplementação da Apple . É altamente improvável que isso mude, mas dependendo do seu nível de paranóia, a documentação da Apple +newparece permitir uma alteração na implementação (e quebre a equivalência) no futuro. Por esse motivo, como "explícito é melhor que implícito" e para continuidade histórica, a comunidade Objective-C geralmente evita +new. No entanto, geralmente é possível identificar os recém-chegados Java ao Objective-C por seu uso obstinado +new.

Barry Wark
fonte
8
Embora isso geralmente seja verdade, também existe um campo a favor da concisão, caso em que apenas é mais explícito quando há uma preocupação clara e presente que o justifique.
Peter DeWeese
27
Eu diminuí a votação disso porque +newexiste desde os dias da NeXT. Se alguma coisa +newé um sinal de alguém que aprendeu objc há muito tempo; Vejo muitas pessoas que vêm de novo para o idioma, ou que o escrevem há anos, mas claramente após o boom do iOS, não têm idéia do que isso +newsignifica. Segundo, como +newé muito antiga e, desde os dias de NeXT, a Apple seria muito insana em modificá-lo de maneira a quebrar o código antigo, especialmente considerando que suas próprias bases de código provavelmente estão repletas dele.
precisa saber é
11
Tenho certeza de que o newidioma vem do Smalltalk. Também é usado no Ruby, e o Objective-C e o Ruby derivam muitas sintaxes e convenções do Smalltalk.
Brendon Roberto
3
Ele permite apenas uma alteração na alocação. Os documentos declaram explicitamente -init serão chamados. Portanto, depende mais se você substituir a alocação.
Kendall Helmstetter Gelner # 8/14
7
Eu realmente não consigo imaginar por que uma solução em que você deve digitar MORE seria preferida (alocação init), especialmente em uma linguagem detalhada como Objective-C, onde salvar pressionamentos de tecla economizará tempo. Esses "desenvolvedores Java obstinados" estão apenas usando suas habilidades analíticas para gastar menos tempo escrevendo código em vez de digitar desnecessariamente caracteres extras que produzem o mesmo resultado funcional.
DiscDev
9

Freqüentemente, você precisará passar argumentos para inite, portanto, usará um método diferente, como [[SomeObject alloc] initWithString: @"Foo"]. Se você está acostumado a escrever isso, tem o hábito de fazê-lo dessa maneira e, portanto, [[SomeObject alloc] init]pode vir mais naturalmente disso [SomeObject new].

Brian Campbell
fonte
7

Uma resposta curta é:

  1. Ambos são iguais. Mas
  2. 'new' funciona apenas com o inicializador básico 'init' e não funcionará com outros inicializadores (por exemplo, initWithString :).
user739711
fonte
3

Para uma observação, eu pessoalmente uso [Foo new]se quero que algo no init seja feito sem usar seu valor de retorno em qualquer lugar. Se você não usar o retorno de [[Foo alloc] init]qualquer lugar, receberá um aviso. Mais ou menos, eu uso [Foo new]para colírio para os olhos.

evdude100
fonte
3

Estou muito atrasado para isso, mas quero mencionar que esse novo é realmente inseguro no Obj-C com o mundo Swift. O Swift criará apenas um método init padrão se você não criar nenhum outro inicializador. A chamada nova em uma classe rápida com um inicializador personalizado causará uma falha. Se você usar o assign / init, o compilador irá reclamar adequadamente que o init não existe.

MurderDev
fonte
1

Se new faz o trabalho para você, também tornará seu código modestamente menor. Caso contrário, você poderia chamar [[SomeClass alloc] init]muitos locais diferentes no seu código, criará um Hot Spot na implementação de new - ou seja, no tempo de execução objc - que reduzirá o número de falhas no cache.

No meu entendimento, se você precisar usar um uso inicializador personalizado [[SomeClass alloc] initCustom].

Se não, use [SomeClass new].

Mike Crawford
fonte
11
Eu argumentaria com "se você precisar usar um inicializador personalizado, use [[SomeClass aloc] initCustom]". Se você precisar de um inicializador personalizado sem nenhum parâmetro, nunca faça algo como o que está sugerindo, substitua a initfunção padrão e use-a. [[SomeClass alloc] init];Se você precisar de parâmetros, ainda assim nunca faça algo assim, faça [[SomeClass alloc] initWith:...];. Por fim, se você substituir a initfunção por uma implementação customizada, poderá newcriar um objeto e ele ainda chamará a initimplementação customizada .
dirtydanee