Utilizzo di alloc init anziché new


344

Imparando Objective-C e leggendo il codice di esempio, noto che gli oggetti vengono generalmente creati utilizzando questo metodo:

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

invece di:

SomeObject *myObject = [SomeObject new];

C'è una ragione per questo, poiché ho letto che sono equivalenti?


12
Non sapevo nemmeno che fosse possibile! Tutto il materiale che ho letto finge che la nuova parola chiave non esista!
Jonathan,

78
In realtà "nuovo" non è una parola chiave in Objective-C, ma NSObject implementa un metodo di classe "nuovo" che chiama semplicemente "alloc" e "init".
Don McCaughey,

3
Jonathan, questo è esattamente ciò che ha portato alla mia domanda. Possono essere funzionalmente equivalenti ma [[alloc] init] è chiaramente il linguaggio dominante.
willc2,

1
Penso che Apple (da quello che ricordo da una delle loro lezioni su iTunes Stanford) ti incoraggi a utilizzare alloc init invece di poter capire il processo di ciò che sta accadendo. Inoltre non usano molto nuovo nel loro codice di esempio, quindi alloc init sembra essere solo una buona abitudine generale che Apple cerca di promuovere.
PostCodeism,

Risposte:


290

Ci sono molte ragioni qui: http://macresearch.org/difference-between-alloc-init-and-new

Alcuni selezionati sono:

  • newnon supporta inizializzatori personalizzati (come initWithString)
  • alloc-init è più esplicito di new

L'opinione generale sembra essere che dovresti usare qualunque cosa tu sia a tuo agio.


8
Se la tua classe usa -init come inizializzatore designato, + new lo chiamerà. Ciò a cui Jeremy si riferisce è se hai un inizializzatore personalizzato che non è -init. -initWithName :, ad esempio.
bbum,

87
Non c'è nulla che ti impedisca di implementare +newWithString:, se lo hai già implementato -initWithString. Non è così comune però. Personalmente uso sempre newquando l'inizializzatore designato è init, solo così breve e dolce.
PeyloW,

11
So che questo è un vecchio thread, ma voglio solo sottolineare che non dovresti implementarlo +newWithString:. Ciò rompe la separazione delle preoccupazioni. Perché quando vuoi solo usare -initcomunque, non c'è motivo di non usarlo +new, però.
Jonathan Sterling,

7
@JonathanSterling: Apple ha molti casi in cui sembrano fare esattamente ciò che sconsigli; per esempio [[NSString alloc] initWithFormat:...]e [NSString stringWithFormat:...]sono entrambi equivalenti. Stai dicendo che Apple ha violato la separazione delle preoccupazioni e non avrebbe dovuto attuarla in questo modo? (Nota: non sto cercando di essere condiscendente; vorrei solo avere maggiori informazioni e sapere se seguire l'esempio di Apple a volte è una cattiva idea.)
Senseful

6
@Senseful Credo che risalga ai giorni precedenti ARC (o garbage collection). Queste due cose non siamo equivalenti. stringWithFormat: restituirebbe una stringa rilasciata automaticamente mentre alloc: init: dovrebbe essere rilasciato manualmente o rilasciato automaticamente, altrimenti causerebbe una perdita di memoria.
msfeldstein,

139

Domanda molto vecchia, ma ho scritto alcuni esempi solo per divertimento - forse lo troverai utile;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

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

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

@end

Nella funzione principale entrambe le affermazioni:

[[InitAllocNewTest alloc] init];

e

[InitAllocNewTest new];

risulta nello stesso output:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...

5
Risposta eccellente! Voglio solo aggiungere che l'utilizzo di + new è ottimo per i casi in cui devi solo usare -init e niente di più specializzato come -initWithSomething: ...
cgossain

Sfortunatamente, questo esempio non è la prova che sono identici. È solo un esempio in cui producono lo stesso risultato.
Vince O'Sullivan,

10
Sfortunatamente, questo esempio non è la prova che sono identici. È solo un esempio in cui accadono producono lo stesso risultato. D'altra parte, questo dimostra che sono diversi ... Prendendo l'esempio sopra, modifica "InitAllocNewTest.h" come segue: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init]non verrà compilato mentre [InitAllocNewTest new]non è interessato. (Scuse per mancanza di interruzioni di linea, ecc.)
Vince O'Sullivan,

1
@ VinceO'Sullivan, buon punto. Questo significa che se si vuole rendere init non disponibile, come in una classe singleton, si dovrebbe disabilitare anche new. Non toccherò qui se i singoli sono buoni o cattivi.
user3099609

Ho una domanda dal codice sopra. perché "return [super init];"? generalmente init è un metodo in cui i membri della classe sono inizializzati, perché il puntatore cambia è molto strano!
Pruthvidhar Rao Nadunooru,

52

+newè equivalente all'implementazione +alloc/-initdi Apple NSObject. È altamente improbabile che questo possa mai cambiare, ma a seconda del livello di paranoia, la documentazione di Apple +newsembra consentire un cambiamento di implementazione (e rompere l'equivalenza) in futuro. Per questo motivo, poiché "esplicito è meglio di implicito" e per continuità storica, la comunità Objective-C generalmente evita +new. Tuttavia, di solito è possibile individuare i recenti arrivati ​​di Java in Objective-C con il loro uso ostinato di +new.


8
Sebbene ciò sia spesso vero, esiste anche un campo a favore della terseness, nel qual caso essere più esplicito solo quando c'è una preoccupazione chiara e presente che lo merita.
Peter DeWeese,

27
Ho annullato il voto perché +newè in circolazione sin dai giorni successivi. Semmai +newqualcosa è un segno di qualcuno che ha imparato objc molto tempo fa; Vedo molte persone che apprendono la lingua o che la scrivono da anni ma chiaramente dopo il boom di iOS, non hanno idea di cosa +newsignifichi. In secondo luogo, poiché +newè molto vecchio e dai tempi del NeXT, Apple sarebbe abbastanza pazza da cambiarlo in un modo che rompe il vecchio codice, specialmente considerando che le loro basi di codice sono probabilmente disseminate di esso.
asveikau,

1
Sono abbastanza sicuro che il newlinguaggio venga da Smalltalk. È anche usato in Ruby, e sia Objective-C che Ruby derivano gran parte della loro sintassi e convenzioni da Smalltalk.
Brendon Roberto,

3
Consente solo una modifica dell'allocazione. Verrà chiamato esplicitamente lo stato -init. Quindi dipende di più se si sostituisce mai l'allocazione.
Kendall Helmstetter Gelner,

7
Non riesco davvero a immaginare perché una soluzione in cui devi digitare ALTRO sia preferita (alloc init), specialmente in un linguaggio così dettagliato come Objective-C in cui il salvataggio dei tasti ti farà risparmiare tempo. Quegli "sviluppatori Java ostinati" stanno solo usando le loro abilità analitiche per passare meno tempo a scrivere codice invece di digitare inutilmente caratteri extra che producono lo stesso risultato funzionale.
DiscDev,

9

Spesso dovrai passare argomenti inite quindi utilizzerai un metodo diverso, ad esempio [[SomeObject alloc] initWithString: @"Foo"]. Se sei abituato a scrivere questo, hai l'abitudine di farlo in questo modo e quindi [[SomeObject alloc] init]potrebbe venire più naturalmente [SomeObject new].


7

Una risposta breve è:

  1. Entrambi sono uguali. Ma
  2. 'new' funziona solo con l'inizializzatore di base 'init' e non funziona con altri inizializzatori (ad esempio initWithString :).

3

Per una nota a margine, uso personalmente [Foo new]se voglio che qualcosa in init sia fatto senza usare il suo valore di ritorno ovunque. Se non si utilizza il reso da [[Foo alloc] init]nessuna parte, verrà visualizzato un avviso. Più o meno, io uso [Foo new]per la gioia degli occhi.


3

Sono in ritardo, ma voglio dire che quel nuovo non è sicuro nel mondo Obj-C con Swift. Swift creerà un metodo init predefinito solo se non si crea alcun altro inizializzatore. Chiamare nuovo su una classe rapida con un inizializzatore personalizzato provocherà un arresto anomalo. Se si utilizza alloc / init, il compilatore si lamenterà correttamente che init non esiste.


1

Se nuovo fa il lavoro per te, anche il tuo codice sarà leggermente più piccolo. Se altrimenti chiamassi [[SomeClass alloc] init]in molti punti diversi del tuo codice, creerai un Hot Spot nell'implementazione di new - cioè, nel runtime objc - che ridurrà il numero di mancati cache.

A mio avviso, se è necessario utilizzare un inizializzatore personalizzato, utilizzare [[SomeClass alloc] initCustom].

In caso contrario, utilizzare [SomeClass new].


1
Discuterei con "se hai bisogno di usare un inizializzatore personalizzato usa [[SomeClass alloc] initCustom]". Se hai bisogno di un inizializzatore personalizzato senza parametri, non fare mai qualcosa come quello che stai suggerendo, sovrascrivi la initfunzione predefinita e usala [[SomeClass alloc] init];Se hai bisogno di parametri, non fare mai qualcosa del genere, fallo [[SomeClass alloc] initWith:...];. Infine, se si sovrascrive la initfunzione con un'implementazione personalizzata, è possibile fare appello newalla creazione di un oggetto, che chiamerà comunque l' initimplementazione personalizzata .
dirtydanee,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.