Yeni yerine ayırma init kullanımı


344

Objective-C öğrenme ve örnek kod okuma, nesneleri genellikle bu yöntem kullanılarak oluşturulduğunu fark:

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

onun yerine:

SomeObject *myObject = [SomeObject new];

Bunun eşdeğer olduğunu okuduğum için bunun bir nedeni var mı?


12
Bunun mümkün olduğunu bile bilmiyordum! Okuduğum tüm materyaller yeni anahtar kelime yokmuş gibi yapıyor!
Jonathan

78
Aslında "yeni" Objective-C'de bir anahtar kelime değildir, ancak NSObject basitçe "tahsis" ve "init" olarak adlandırılan "yeni" bir sınıf yöntemi uygular.
Don McCaughey

3
Jonathan, sorumu tam olarak harekete geçiren buydu. İşlevsel olarak eşdeğer olabilirler, ancak [[tahsis] init] açıkça baskın deyimdir.
willc2

1
Bence Apple (iTunes Stanford derslerinden birinden hatırlayabildiğim kadarıyla) sadece bunun yerine tahsis init'i kullanmanızı teşvik ediyor, böylece neler olduğunu anlayabiliyorsunuz. Ayrıca örnek kodlarında yeni bir şey kullanmazlar, bu nedenle tahsis init, Apple'ın tanıtmaya çalıştığı genel bir iyi alışkanlık gibi görünüyor.
PostCodeism

Yanıtlar:


290

Burada bir sürü neden var: http://macresearch.org/difference-between-alloc-init-and-new

Seçilenlerden bazıları:

  • newözel başlatıcıları desteklemiyor (gibi initWithString)
  • alloc-init daha açık new

Genel görüş, rahat ettiğiniz her şeyi kullanmanız gerektiği gibi görünüyor.


8
Sınıfınız belirtilen başlatıcı olarak -init kullanıyorsa, + new onu çağırır. Jeremy'nin bahsettiği şey, -init olmayan özel bir başlatıcısı varsa. -initWithName:, örneğin.
bbum

87
Daha +newWithString:önce uyguladıysanız, uygulamanızı da engelleyen hiçbir şey yoktur -initWithString. Ama o kadar da yaygın değil. Şahsen her newzaman belirtilen başlatıcı init, çok kısa ve tatlı olduğunda kullanırım.
PeyloW

11
Bunun eski bir konu olduğunu biliyorum, ama sadece uygulamaman gerektiğini vurgulamak istiyorum +newWithString:. Endişelerin ayrılmasını koparır. Sadece kullanmak istediğinizde için -initzaten hiçbir neden sadece kullanımına orada değil +newgerçi.
Jonathan Sterling

7
@JonathanSterling: Apple, tam olarak önerdiğiniz şeyi yapıyor gibi göründüğü birçok örneğe sahiptir; örneğin [[NSString alloc] initWithFormat:...]ve [NSString stringWithFormat:...]her ikisi de eşdeğerdir. Apple'ın endişelerin ayrılmasını ihlal ettiğini ve bunu bu şekilde uygulamaması gerektiğini mi söylüyorsunuz? (Not: küçümseyici olmaya çalışmıyorum; Daha fazla bilgi almak istiyorum ve Apple'ın
ipucunu takip etmenin

6
@Senseful Ben ARC (veya çöp toplama) önceki günlere kadar olduğuna inanıyorum. Bu iki şey eşdeğer değiliz. stringWithFormat: tahsis edilirken otomatik olarak yayınlanmış bir dize döndürür: init: manuel olarak serbest bırakılması veya otomatik olarak yayınlanması gerekir, aksi takdirde bellek sızıntısına neden olur.
msfeldstein

139

Çok eski bir soru, ama sadece eğlence için bir örnek yazdım - belki de yararlı bulacaksınız;)

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

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

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

@end

Ana işlevde her iki ifade:

[[InitAllocNewTest alloc] init];

ve

[InitAllocNewTest new];

aynı çıktıyla sonuçlanır:

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

5
Mükemmel cevap! Sadece -init ve -initWithSomething gibi daha özel bir şey kullanmanız gereken durumlar için + new kullanmanın harika olduğunu eklemek isterim: ...
cgossain

Ne yazık ki, bu örnek aynı olduklarının kanıtı değildir. Bu sadece aynı sonucu ürettikleri bir örnektir.
Vince O'Sullivan

10
Ne yazık ki, bu örnek aynı olduklarının kanıtı değildir. Sadece aynı sonucu elde ettikleri bir örnektir. Öte yandan, bu onların farklı olduğunu kanıtlıyor ... Yukarıdaki örneği alarak, "InitAllocNewTest.h" aşağıdaki gibi değiştirin: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end etkilenmezken [[InitAllocNewTest alloc] init]derlenmez [InitAllocNewTest new]. (Satır sonu olmaması nedeniyle özür dileriz)
Vince O'Sullivan

1
@ VinceO'Sullivan, iyi bir nokta. Bu, eğer tek bir sınıfta olduğu gibi init'i kullanılamaz hale getirmek istiyorsa, yeniyi de devre dışı bırakmanız gerektiği anlamına gelir. Burada singletonların iyi mi kötü mü olduğuna değinmeyeceğim.
user3099609

Yukarıdaki koddan bir sorum var. neden "dönüş [süper init];"? genellikle init, sınıf üyelerinin başlatıldığı, işaretçi değişikliklerinin neden çok garip olduğu bir yöntemdir!
Pruthvidhar Rao Nadunooru

52

+new+alloc/-initApple'ın NSObjectuygulanmasına eşdeğerdir . Bunun değişmesi pek olası değildir, ancak paranoya seviyenize bağlı olarak, Apple'ın dokümantasyonunun +newgelecekte uygulama değişikliğine (ve eşdeğerliğini bozmasına) izin verdiği görülmektedir. Bu nedenle, "açık, örtük olmaktan daha iyidir" ve tarihsel devamlılık için, Objective-C topluluğu genellikle bundan kaçınır +new. Bununla birlikte, genellikle Java'nın son kullanıcılarını, amaçlanan kullanımlarıyla Objective-C'ye görebilirsiniz +new.


8
Bu genellikle doğru olmasına rağmen, aynı zamanda rahmetlilik lehine bir kamp da vardır, bu durumda sadece onu garanti eden açık ve mevcut bir endişe olduğunda daha açık olmak.
Peter DeWeese

27
Bunu reddettim çünkü +newNeXT günlerinden beri var. Eğer bir şey +newuzun zaman önce objc öğrenen birinin bir işaretine aitse; Dile yeni gelen ya da yıllardır yazmış, ancak iOS patlamasından sonra açıkça yazılan birçok insanın ne +newanlama geldiğini bilmiyorum . İkincisi, +newçok eski olduğu gibi ve NeXT günlerinden beri, Apple, özellikle kendi kod tabanlarının muhtemelen onunla dolu olduğu düşünüldüğünde, eski kodu kıran bir şekilde değiştirmek için oldukça çılgınca olurdu.
asveikau

1
newDeyimin Smalltalk'tan geldiğinden eminim . Ayrıca Ruby'de kullanılır ve hem Objective-C hem de Ruby, sözdiziminin ve kurallarının çoğunu Smalltalk'tan türetir.
Brendon Roberto

3
Yalnızca tahsis değişikliğine izin verir. Açıkça devlet -init dokümanları çağrılır. Bu nedenle, daha fazla ayırmayı geçersiz kılmanıza bağlıdır.
Kendall Helmstetter Gelner

7
Gerçekten daha fazla yazmanız gereken bir çözümün neden tercih edilebildiğini (ayırma init) gerçekten hayal bile edemiyorum, özellikle Objective-C gibi ayrıntılı bir dilde, zamandan tasarruf etmenizi sağlayacak. Bu "dogged Java geliştiricileri", aynı işlevsel sonucu üreten ekstra karakterleri gereksiz yere yazmak yerine kod yazmak için daha az zaman harcamak için analitik becerilerini kullanıyorlar.
DiscDev

9

Sık sık, argümanları iletmeniz gerekecek initve böylece farklı bir yöntem kullanacaksınız [[SomeObject alloc] initWithString: @"Foo"]. Bunu yazmaya alışkınsanız, bunu bu şekilde yapma alışkanlığına sahip olursunuz ve böylece [[SomeObject alloc] init]daha doğal olarak gelebilir [SomeObject new].


7

Bir Kısa Yanıt:

  1. İkisi de aynı. Fakat
  2. 'new' yalnızca temel 'init' başlatıcısı ile çalışır ve diğer başlatıcılarla çalışmaz (örneğin initWithString :).

3

Yan not için, [Foo new]init'te bir şeyin herhangi bir yerde dönüş değeri kullanmadan yapılmasını istiyorsanız kişisel olarak kullanırım . Herhangi bir yerin iadesini kullanmazsanız [[Foo alloc] init]bir uyarı alırsınız. Az ya da çok, [Foo new]göz şekeri için kullanıyorum .


3

Buna çok geç kaldım ama Swift dünyasında Obj-C'de yeni olanın aslında güvensiz olduğunu belirtmek istiyorum. Swift, yalnızca başka bir başlatıcı oluşturmazsanız varsayılan bir init yöntemi oluşturur. Özel bir başlatıcı ile hızlı bir sınıfta yeni çağrı yapmak çökmeye neden olur. Tahsis / init kullanırsanız, derleyici init'in mevcut olmadığını doğru şekilde şikayet edecektir.


1

Yeni iş sizin için yaparsa, kodunuzu mütevazi bir şekilde daha küçük hale getirecektir. Aksi halde [[SomeClass alloc] init]kodunuzdaki birçok farklı yeri ararsanız , yeni uygulamasında (yani, objc çalışma zamanında) önbellek kaçırma sayısını azaltacak bir Etkin Nokta oluşturacaksınız.

Anladığım kadarıyla, özel bir başlatıcı kullanımı kullanmanız gerekiyorsa [[SomeClass alloc] initCustom].

Eğer yapmazsan, kullan [SomeClass new].


1
Ben "özel bir başlatıcısı [[SomeClass ayır] initCustom] kullanın gerekiyorsa" ile tartışmak istiyorum. Herhangi bir parametre olmadan özel bir başlatıcıya ihtiyacınız varsa, asla önerdiğiniz gibi bir şey yapmayın, sadece varsayılan initişlevi geçersiz kılın ve kullanın [[SomeClass alloc] init];Parametrelere ihtiyacınız varsa, yine de böyle bir şey yapmayın [[SomeClass alloc] initWith:...];. Son olarak, initişlevi özel bir uygulamayla geçersiz kılarsanız, newbir nesne oluşturduktan sonra çağırabilirsiniz ve yine de özel inituygulamayı çağıracaktır .
dirtydanee
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.