Uso de alloc init en lugar de nuevo

344

Aprendiendo Objective-C y leyendo código de muestra, noto que los objetos generalmente se crean usando este método:

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

en vez de:

SomeObject *myObject = [SomeObject new];

¿Hay alguna razón para esto, ya que he leído que son equivalentes?

willc2
fuente
12
¡Ni siquiera sabía que eso era posible! ¡Todo el material que he leído pretende que la nueva palabra clave no existe!
Jonathan
78
En realidad, "nuevo" no es una palabra clave en Objective-C, pero NSObject implementa un método de clase "nuevo" que simplemente llama "alloc" e "init".
Don McCaughey
3
Jonathan, eso es exactamente lo que provocó mi pregunta. Pueden ser funcionalmente equivalentes, pero [[alloc] init] es claramente el idioma dominante.
willc2
1
Creo que Apple (por lo que puedo recordar de una de sus conferencias de iTunes Stanford) simplemente lo alienta a usar alloc init en su lugar para que pueda comprender el proceso de lo que está sucediendo. Tampoco usan mucho nuevo en su código de muestra, por lo que alloc init parece ser solo un buen hábito general que Apple intenta promover.
PostCodeism

Respuestas:

290

Aquí hay muchas razones: http://macresearch.org/difference-between-alloc-init-and-new

Algunos seleccionados son:

  • newno admite inicializadores personalizados (como initWithString)
  • alloc-init es más explícito que new

La opinión general parece ser que debe usar lo que le resulte más cómodo.

Jeremy Stanley
fuente
8
Si su clase usa -init como el inicializador designado, + new lo llamará. A lo que Jeremy se refiere es si tienes un inicializador personalizado que no es -init. -initWithName :, por ejemplo.
bbum
87
No hay nada que le impida implementar +newWithString:también, si ya lo implementó -initWithString. Aunque no es tan común. Personalmente, siempre uso newcuando el inicializador designado es init, muy corto y dulce.
PeyloW
11
Sé que este es un hilo viejo, pero solo quiero enfatizar que no debes implementarlo +newWithString:. Eso rompe la separación de las preocupaciones. Sin embargo, para cuando solo quiera usarlo -init, no hay razón para no usarlo +new.
Jonathan Sterling
77
@ JonathanSterling: Apple tiene muchas instancias en las que parecen estar haciendo exactamente lo que desaconsejas; por ejemplo [[NSString alloc] initWithFormat:...]y [NSString stringWithFormat:...]son ambos equivalentes. ¿Estás diciendo que Apple violó la separación de preocupaciones y no debería haberlo implementado de esta manera? (Nota: No estoy tratando de ser condescendiente; Me gustaría obtener más información y saber si siguiendo el ejemplo de Apple es a veces una mala idea.)
Senseful
66
@Senseful Creo que se remonta a los días anteriores a ARC (o recolección de basura). Esas dos cosas no somos equivalentes. stringWithFormat: devolvería una cadena liberada automáticamente mientras alloc: init: necesitaría liberarse manualmente o liberarse automáticamente, o de lo contrario causaría una pérdida de memoria.
msfeldstein
139

Pregunta muy antigua, pero he escrito algún ejemplo solo por diversión, tal vez lo encuentre útil;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

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

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

@end

En función principal ambas afirmaciones:

[[InitAllocNewTest alloc] init];

y

[InitAllocNewTest new];

resultar en la misma salida:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...
guitar_freak
fuente
55
Excelente respuesta! Sólo quiero añadir que usando + nueva es ideal para los casos en los que sólo tendrá que utilizar -init y nada más especializada como -initWithSomething: ...
cgossain
Desafortunadamente, este ejemplo no es prueba de que sean idénticos. Es solo un ejemplo donde producen el mismo resultado.
Vince O'Sullivan
10
Desafortunadamente, este ejemplo no es prueba de que sean idénticos. Es solo un ejemplo donde suceden producen el mismo resultado. Por otro lado, esto prueba que son diferentes ... Tomando el ejemplo anterior, modifique "InitAllocNewTest.h" de la siguiente manera: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init]no se compilará mientras [InitAllocNewTest new]no se vea afectado. (Disculpas por la falta de saltos de línea, etc.)
Vince O'Sullivan
1
@ VinceO'Sullivan, buen punto. Esto significa que si uno quiere hacer que init no esté disponible, como en una clase singleton, también debería deshabilitar new. No tocaré aquí si los singletons son buenos o malos.
user3099609
Tengo una pregunta del código anterior. ¿por qué "return [super init];" generalmente init es un método donde los miembros de la clase se inicializan, ¡por qué el puntero cambia es muy extraño!
Pruthvidhar Rao Nadunooru
52

+newes equivalente a +alloc/-initen la NSObjectimplementación de Apple . Es muy poco probable que esto cambie, pero dependiendo de su nivel de paranoia, la documentación de Apple +newparece permitir un cambio de implementación (y romper la equivalencia) en el futuro. Por esta razón, porque "explícito es mejor que implícito" y para la continuidad histórica, la comunidad Objective-C generalmente evita +new. Sin embargo, por lo general, puede detectar a los recién llegados de Java a Objective-C por su uso obstinado de +new.

Barry Wark
fuente
8
Aunque esto es a menudo cierto, también hay un campo a favor de la brevedad, en cuyo caso solo será más explícito cuando haya una preocupación clara y presente que lo justifique.
Peter DeWeese
27
Lo rechacé porque +newha existido desde los días NeXT. Si algo +newes una señal de alguien que aprendió objc hace mucho tiempo; Veo a muchas personas que se familiarizan con el idioma, o que incluso lo han estado escribiendo durante años, pero claramente después del boom de iOS, no tienen idea de lo que +newsignifica. En segundo lugar, como +newes muy antiguo y desde los días NeXT, Apple sería bastante loco cambiarlo de una manera que rompa el código antiguo, especialmente teniendo en cuenta que sus propias bases de código probablemente estén plagadas de él.
asveikau
1
Estoy bastante seguro de que el newidioma proviene de Smalltalk. También se usa en Ruby, y tanto Objective-C como Ruby obtienen gran parte de su sintaxis y convenciones de Smalltalk.
Brendon Roberto
3
Solo permite un cambio en la asignación. Se llamará a los documentos explícitamente state -init. Por lo tanto, depende más si anula la asignación alguna vez.
Kendall Helmstetter Gelner
77
Realmente no puedo imaginar por qué sería preferible una solución en la que tenga que escribir MORE (alloc init), especialmente en un lenguaje tan detallado como Objective-C donde guardar las pulsaciones de teclas le ahorrará tiempo. Esos "desarrolladores de Java persistentes" solo están usando sus habilidades analíticas para pasar menos tiempo escribiendo código en lugar de escribir innecesariamente caracteres adicionales que producen el mismo resultado funcional.
DiscDev
9

Con frecuencia, necesitará pasar argumentos inity, por lo tanto, utilizará un método diferente, como [[SomeObject alloc] initWithString: @"Foo"]. Si está acostumbrado a escribir esto, tiene el hábito de hacerlo de esta manera y, por [[SomeObject alloc] init]lo tanto, puede ser más natural [SomeObject new].

Brian Campbell
fuente
7

Una respuesta corta es:

  1. Ambos son lo mismo. Pero
  2. 'nuevo' solo funciona con el inicializador básico 'init', y no funcionará con otros inicializadores (por ejemplo, initWithString :).
usuario739711
fuente
3

Para una nota al margen, yo personalmente uso [Foo new]si quiero que se haga algo en init sin usar su valor de retorno en ningún lado. Si no utiliza la devolución de [[Foo alloc] init]ningún lugar, recibirá una advertencia. Más o menos, lo uso [Foo new]para dulces visuales.

evdude100
fuente
3

Llegué muy tarde a esto, pero quiero mencionar que esa nueva realidad no es segura en el mundo de Obj-C con Swift. Swift solo creará un método de inicio predeterminado si no crea ningún otro inicializador. Llamar nuevo en una clase rápida con un inicializador personalizado provocará un bloqueo. Si usa alloc / init, el compilador se quejará correctamente de que init no existe.

AsesinatoDev
fuente
1

Si nuevo hace el trabajo por usted, también hará que su código sea un poco más pequeño. Si de lo contrario llamarías[[SomeClass alloc] init] a muchos lugares diferentes en su código, creará un Hot Spot en la implementación de la nueva, es decir, en el tiempo de ejecución objc, que reducirá la cantidad de errores de caché.

Según tengo entendido, si necesita usar un inicializador personalizado, use [[SomeClass alloc] initCustom] .

Si no lo haces, úsalo [SomeClass new].

Mike Crawford
fuente
1
Yo diría que "si necesita usar un inicializador personalizado use [[SomeClass alloc] initCustom]". Si necesita un inicializador personalizado sin ningún parámetro, nunca haga algo como lo que sugiere, simplemente anule la initfunción predeterminada y úsela. [[SomeClass alloc] init];Si necesita parámetros, nunca haga algo así, hágalo [[SomeClass alloc] initWith:...];. Por último, si anula la initfunción con una implementación personalizada, puede llamar newal crear un objeto, y seguirá llamando a la initimplementación personalizada .
dirtydanee