Verwendung von alloc init anstelle von new

344

Wenn ich Objective-C lerne und Beispielcode lese, stelle ich fest, dass Objekte normalerweise mit dieser Methode erstellt werden:

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

anstatt:

SomeObject *myObject = [SomeObject new];

Gibt es einen Grund dafür, da ich gelesen habe, dass sie gleichwertig sind?

willc2
quelle
12
Ich wusste nicht einmal, dass das möglich ist! Das gesamte Material, das ich gelesen habe, gibt vor, dass das neue Schlüsselwort nicht existiert!
Jonathan
78
Eigentlich ist "new" kein Schlüsselwort in Objective-C, aber NSObject implementiert eine Klassenmethode "new", die einfach "alloc" und "init" aufruft.
Don McCaughey
3
Jonathan, genau das hat meine Frage ausgelöst. Sie mögen funktional äquivalent sein, aber [[alloc] init] ist eindeutig die dominierende Redewendung.
Willc2
1
Ich denke, Apple (soweit ich mich an einen ihrer iTunes Stanford-Vorträge erinnern kann) ermutigt Sie nur, stattdessen alloc init zu verwenden, damit Sie den Prozess des Geschehens verstehen können. Sie verwenden auch nicht viel Neues in ihrem Beispielcode, daher scheint alloc init nur eine allgemein gute Angewohnheit zu sein, die Apple zu fördern versucht.
PostCodeism

Antworten:

290

Hier gibt es eine Reihe von Gründen: http://macresearch.org/difference-between-alloc-init-and-new

Einige ausgewählte sind:

  • newunterstützt keine benutzerdefinierten Initialisierer (wie initWithString)
  • alloc-init ist expliziter als new

Die allgemeine Meinung scheint zu sein, dass Sie alles verwenden sollten, was Sie möchten.

Jeremy Stanley
quelle
8
Wenn Ihre Klasse -init als festgelegten Initialisierer verwendet, ruft + new ihn auf. Jeremy bezieht sich darauf, wenn Sie einen benutzerdefinierten Initialisierer haben, der nicht -init ist. -initWithName:, zum Beispiel.
bbum
87
Nichts hindert Sie daran, ebenfalls zu implementieren +newWithString:, wenn Sie bereits implementiert haben -initWithString. Nicht so häufig. Persönlich benutze ich immer, newwenn der vorgesehene Initialisierer initso kurz und bündig ist.
PeyloW
11
Ich weiß, dass dies ein alter Thread ist, aber ich möchte nur betonen, dass Sie nicht implementieren sollten +newWithString:. Das bricht die Trennung von Bedenken. Wenn Sie es -inittrotzdem nur verwenden möchten , gibt es keinen Grund, es nicht nur zu verwenden +new.
Jonathan Sterling
7
@ JonathanSterling: Apple hat viele Fälle, in denen sie genau das zu tun scheinen, von dem Sie abraten. zum Beispiel [[NSString alloc] initWithFormat:...]und [NSString stringWithFormat:...]sind beide gleichwertig. Wollen Sie damit sagen, dass Apple gegen die Trennung von Bedenken verstoßen hat und dies nicht auf diese Weise hätte implementieren sollen? (Hinweis: Ich versuche nicht herablassend zu sein; ich möchte nur mehr Informationen erhalten und wissen, ob es manchmal eine schlechte Idee ist, Apples Führung zu
folgen
6
@Senseful Ich glaube, das geht auf die Tage vor ARC (oder Garbage Collection) zurück. Diese beiden Dinge sind nicht gleichwertig. stringWithFormat: würde eine automatisch freigegebene Zeichenfolge zurückgeben, während alloc: init: manuell freigegeben oder automatisch freigegeben werden müsste, da dies sonst zu einem Speicherverlust führen würde.
Msfeldstein
139

Sehr alte Frage, aber ich habe ein Beispiel nur zum Spaß geschrieben - vielleicht findest du es nützlich;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

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

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

@end

In der Hauptfunktion beide Aussagen:

[[InitAllocNewTest alloc] init];

und

[InitAllocNewTest new];

Ergebnis in der gleichen Ausgabe:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...
Gitarrenfreak
quelle
5
Hervorragende Antwort! Ich möchte nur hinzufügen, dass die Verwendung von + new ideal für Fälle ist, in denen Sie nur -init und nichts spezielleres wie -initWithSomething: ...
cgossain
Leider ist dieses Beispiel kein Beweis dafür, dass sie identisch sind. Es ist nur ein Beispiel, wo sie das gleiche Ergebnis erzielen.
Vince O'Sullivan
10
Leider ist dieses Beispiel kein Beweis dafür, dass sie identisch sind. Es ist nur ein Beispiel, wo sie das gleiche Ergebnis erzielen. Auf der anderen Seite beweist dies, dass sie unterschiedlich sind ... Ändern Sie im obigen Beispiel "InitAllocNewTest.h" wie folgt: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init]wird nicht kompiliert, solange es nicht [InitAllocNewTest new]betroffen ist. (Entschuldigung für fehlende Zeilenumbrüche usw.)
Vince O'Sullivan
1
@ VinceO'Sullivan, guter Punkt. Das heißt, wenn man init nicht verfügbar machen möchte, wie in einer Singleton-Klasse, sollte man auch new deaktivieren. Ich werde hier nicht darauf eingehen, ob Singletons gut oder schlecht sind.
user3099609
Ich habe eine Frage aus dem obigen Code. warum "return [super init];"? Im Allgemeinen ist init eine Methode, bei der Mitglieder der Klasse initialisiert werden. Warum sich der Zeiger ändert, ist sehr seltsam!
Pruthvidhar Rao Nadunooru
52

+newentspricht +alloc/-initder NSObjectImplementierung von Apple . Es ist höchst unwahrscheinlich, dass sich dies jemals ändern wird. Abhängig von Ihrem Paranoia-Level +newscheint die Dokumentation von Apple für eine Änderung der Implementierung (und einen Verstoß gegen die Äquivalenz) in der Zukunft zu ermöglichen. Aus diesem Grund vermeidet die Objective-C-Community im Allgemeinen, weil "explizit ist besser als implizit" und aus Gründen der historischen Kontinuität +new. In der Regel können Sie jedoch die jüngsten Java-Benutzer von Objective-C anhand ihrer hartnäckigen Verwendung von erkennen +new.

Barry Wark
quelle
8
Obwohl dies oft zutrifft, gibt es auch ein Lager zugunsten der Knappheit. In diesem Fall ist es nur dann expliziter, wenn ein klares und gegenwärtiges Anliegen vorliegt, das dies rechtfertigt.
Peter DeWeese
27
Ich habe dies abgelehnt, weil +newes das seit den nächsten Tagen gibt. Wenn irgendetwas +newein Zeichen für jemanden ist, der vor langer Zeit das Objekt gelernt hat; Ich sehe viele Leute, die frisch in die Sprache kommen oder die sie sogar schon seit Jahren schreiben, aber eindeutig nach dem iOS-Boom keine Ahnung haben, was das +newbedeutet. Zweitens +newwäre Apple , wie es sehr alt ist und seit den nächsten Tagen, ziemlich verrückt, es so zu ändern, dass alter Code kaputt geht, insbesondere wenn man bedenkt, dass ihre eigenen Codebasen wahrscheinlich damit übersät sind.
Asveikau
1
Ich bin mir ziemlich sicher, dass die newRedewendung von Smalltalk stammt. Es wird auch in Ruby verwendet, und sowohl Objective-C als auch Ruby leiten einen Großteil ihrer Syntax und Konventionen von Smalltalk ab.
Brendon Roberto
3
Es ist nur eine Änderung der Zuordnung möglich. Die Dokumente geben ausdrücklich an, dass -init aufgerufen wird. Es hängt also mehr davon ab, ob Sie die Zuweisung jemals überschreiben.
Kendall Helmstetter Gelner
7
Ich kann mir nicht wirklich vorstellen, warum eine Lösung, bei der Sie MEHR eingeben müssen, bevorzugt wird (alloc init), insbesondere in einer so ausführlichen Sprache wie Objective-C, in der das Speichern von Tastenanschlägen Zeit spart. Diese "hartnäckigen Java-Entwickler" verwenden nur ihre analytischen Fähigkeiten, um weniger Zeit mit dem Schreiben von Code zu verbringen, anstatt unnötig zusätzliche Zeichen einzugeben, die das gleiche funktionale Ergebnis erzielen.
DiscDev
9

Häufig müssen Sie Argumente an übergeben, initsodass Sie eine andere Methode verwenden, z [[SomeObject alloc] initWithString: @"Foo"]. Wenn Sie es gewohnt sind, dies zu schreiben, gewöhnen Sie sich an, dies so zu tun, und dies [[SomeObject alloc] init]kann natürlicher sein [SomeObject new].

Brian Campbell
quelle
7

Eine kurze Antwort lautet:

  1. Beide sind gleich. Aber
  2. 'new' funktioniert nur mit dem grundlegenden 'init'-Initialisierer und nicht mit anderen Initialisierern (z. B. initWithString :).
user739711
quelle
3

Als Randnotiz verwende ich persönlich, [Foo new]wenn ich möchte, dass etwas in init ausgeführt wird, ohne den Rückgabewert irgendwo zu verwenden. Wenn Sie die Rückgabe von [[Foo alloc] init]nirgendwo verwenden, erhalten Sie eine Warnung. Mehr oder weniger verwende ich als [Foo new]Augenweide.

evdude100
quelle
3

Ich bin sehr spät dran, aber ich möchte erwähnen, dass das Neue in der Obj-C mit Swift-Welt tatsächlich unsicher ist. Swift erstellt nur dann eine Standard-Init-Methode, wenn Sie keinen anderen Initialisierer erstellen. Das Aufrufen einer neuen schnellen Klasse mit einem benutzerdefinierten Initialisierer führt zu einem Absturz. Wenn Sie alloc / init verwenden, beschwert sich der Compiler ordnungsgemäß darüber, dass init nicht vorhanden ist.

MurderDev
quelle
1

Wenn new den Job für Sie erledigt, wird Ihr Code auch geringfügig kleiner. Wenn Sie sonst anrufen würden[[SomeClass alloc] init] an vielen verschiedenen Stellen in Ihrem Code , erstellen Sie in der Implementierung von new - dh in der objc-Laufzeit - einen Hot Spot, der die Anzahl Ihrer Cache-Fehlschläge verringert.

Nach meinem Verständnis, wenn Sie einen benutzerdefinierten Initialisierer verwenden müssen [[SomeClass alloc] initCustom] .

Wenn nicht, verwenden Sie [SomeClass new].

Mike Crawford
quelle
1
Ich würde mit "Wenn Sie einen benutzerdefinierten Initialisierer verwenden müssen, verwenden Sie [[SomeClass alloc] initCustom]" argumentieren. Wenn Sie einen benutzerdefinierten Initialisierer ohne Parameter benötigen, tun Sie niemals etwas, wie Sie es vorschlagen, überschreiben Sie einfach die Standardfunktion initund verwenden Sie sie. [[SomeClass alloc] init];Wenn Sie Parameter benötigen, tun Sie dies niemals [[SomeClass alloc] initWith:...];. Wenn Sie die initFunktion mit einer benutzerdefinierten Implementierung überschreiben , können Sie newbeim Erstellen eines Objekts aufrufen , und die benutzerdefinierte initImplementierung wird weiterhin aufgerufen .
Dirtydanee