Penggunaan alokasi init bukan yang baru

344

Belajar Objective-C dan membaca kode sampel, saya perhatikan bahwa objek biasanya dibuat menggunakan metode ini:

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

dari pada:

SomeObject *myObject = [SomeObject new];

Apakah ada alasan untuk ini, karena saya telah membaca bahwa mereka setara?

willc2
sumber
12
Aku bahkan tidak tahu itu mungkin! Semua materi yang saya baca berpura-pura seperti kata kunci baru tidak ada!
Jonathan
78
Sebenarnya "baru" bukan kata kunci dalam Objective-C, tetapi NSObject mengimplementasikan metode kelas "baru" yang hanya memanggil "alokasi" dan "init".
Don McCaughey
3
Jonathan, itulah yang mendorong pertanyaanku. Mereka mungkin secara fungsional setara tetapi [[mengalokasikan] init] jelas merupakan ungkapan dominan.
willc2
1
Saya pikir Apple (dari apa yang dapat saya ingat dari salah satu kuliah iTunes Stanford mereka) hanya mendorong Anda untuk menggunakan alokasi init sehingga Anda dapat memahami proses apa yang terjadi. Mereka juga tidak menggunakan banyak hal baru dalam kode sampel mereka, jadi alokasikan init tampaknya hanya kebiasaan baik umum yang coba dipromosikan Apple.
PostCodeism

Jawaban:

290

Ada banyak alasan di sini: http://macresearch.org/difference-between-alloc-init-and-new

Beberapa yang dipilih adalah:

  • newtidak mendukung inisialisasi khusus (seperti initWithString)
  • alloc-init lebih eksplisit daripada new

Pendapat umum tampaknya adalah bahwa Anda harus menggunakan apa pun yang Anda sukai.

Jeremy Stanley
sumber
8
Jika kelas Anda menggunakan -init sebagai inisialisasi yang ditunjuk, + baru akan memanggilnya. Yang dimaksud Jeremy adalah jika Anda memiliki penginisialisasi khusus yang bukan -init. -initWithName :, misalnya.
bbum
87
Tidak ada yang menghentikan Anda dari penerapan +newWithString:juga, jika Anda sudah menerapkan -initWithString. Tapi tidak begitu umum. Secara pribadi saya selalu menggunakan newketika initializer yang ditunjuk init, hanya soo pendek dan manis.
PeyloW
11
Saya tahu ini adalah utas lama, tetapi saya hanya ingin menekankan bahwa Anda seharusnya tidak menerapkannya +newWithString:. Itu mematahkan pemisahan kekhawatiran. Karena ketika Anda hanya ingin menggunakannya -init, tidak ada alasan untuk tidak menggunakannya +new.
Jonathan Sterling
7
@ JonathanSterling: Apple memiliki banyak contoh di mana mereka tampaknya melakukan hal yang Anda sarankan; misalnya [[NSString alloc] initWithFormat:...]dan [NSString stringWithFormat:...]keduanya setara. Apakah Anda mengatakan Apple melanggar pemisahan kekhawatiran dan seharusnya tidak menerapkannya dengan cara ini? (Catatan: Saya tidak berusaha untuk merendahkan; Saya hanya ingin mendapatkan lebih banyak info, dan tahu apakah mengikuti petunjuk Apple terkadang merupakan ide yang buruk.)
Senseful
6
@Senseful Saya percaya bahwa tanggal kembali ke hari-hari sebelum ARC (atau pengumpulan sampah). Dua hal itu kita tidak setara. stringWithFormat: akan mengembalikan string autoreleased saat mengalokasikan: init: perlu dilepaskan secara manual atau autoreleased, jika tidak akan menyebabkan kebocoran memori.
msfeldstein
139

Pertanyaan yang sangat lama, tapi saya telah menulis beberapa contoh hanya untuk bersenang-senang - mungkin Anda akan menemukan itu berguna

#import "InitAllocNewTest.h"

@implementation InitAllocNewTest

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

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

@end

Dalam fungsi utama kedua pernyataan:

[[InitAllocNewTest alloc] init];

dan

[InitAllocNewTest new];

menghasilkan output yang sama:

2013-03-06 16:45:44.125 XMLTest[18370:207] Allocating...
2013-03-06 16:45:44.128 XMLTest[18370:207] Initializing...
guitar_freak
sumber
5
Jawaban yang sangat bagus! Hanya ingin menambahkan bahwa menggunakan + baru sangat bagus untuk kasus-kasus di mana Anda hanya perlu menggunakan -init dan tidak ada yang lebih khusus seperti -initWithSomething: ...
cgossain
Sayangnya, contoh ini bukan bukti bahwa mereka identik. Ini hanyalah contoh di mana mereka menghasilkan hasil yang sama.
Vince O'Sullivan
10
Sayangnya, contoh ini bukan bukti bahwa mereka identik. Ini hanyalah contoh di mana mereka terjadi menghasilkan hasil yang sama. Di sisi lain, ini membuktikan bahwa mereka berbeda ... Mengambil contoh di atas, modifikasi "InitAllocNewTest.h" sebagai berikut: @interface InitAllocNewTest: NSObject - (instancetype) __unavailable init; @end [[InitAllocNewTest alloc] init]tidak akan mengkompilasi sementara [InitAllocNewTest new]tidak terpengaruh. (Permintaan maaf karena tidak ada jeda baris, dll.)
Vince O'Sullivan
1
@ VinceO'Sullivan, poin bagus. Ini berarti jika seseorang ingin membuat init tidak tersedia, seperti dalam kelas tunggal, ia juga harus menonaktifkan yang baru. Saya tidak akan menyentuh di sini apakah lajang baik atau buruk.
user3099609
Saya punya pertanyaan dari kode di atas. mengapa "return [super init];"? umumnya init adalah metode di mana anggota kelas diinisialisasi, mengapa perubahan pointer sangat aneh!
Pruthvidhar Rao Nadunooru
52

+newsetara dengan +alloc/-initdalam NSObjectimplementasi Apple . Sangat tidak mungkin hal ini akan pernah berubah, tetapi tergantung pada tingkat paranoia Anda, dokumentasi Apple untuk +newtampaknya memungkinkan perubahan implementasi (dan melanggar kesetaraan) di masa depan. Untuk alasan ini, karena "eksplisit lebih baik daripada implisit" dan untuk kelangsungan sejarah, komunitas Objective-C umumnya menghindari +new. Anda dapat, bagaimanapun, biasanya melihat pendatang Jawa baru-baru ini ke Objective-C dengan penggunaan mereka +new.

Barry Wark
sumber
8
Meskipun ini sering benar, ada sebuah kamp yang mendukung kesederhanaan juga, di mana kasus hanya menjadi lebih eksplisit ketika ada kepedulian yang jelas dan saat ini yang menjaminnya.
Peter DeWeese
27
Saya menurunkan ini karena +newsudah ada sejak zaman NeXT. Jika ada +newsesuatu yang merupakan pertanda seseorang yang sudah lama belajar objc; Saya melihat banyak orang yang baru mengenal bahasa ini, atau yang bahkan telah menulisnya selama bertahun-tahun tetapi jelas setelah boom iOS, tidak tahu apa +newartinya. Kedua, karena +newsudah sangat tua dan sejak masa NeXT, Apple akan sangat gila untuk mengubahnya dengan cara yang merusak kode lama, terutama mengingat basis kode mereka sendiri mungkin dikotori dengan itu.
asveikau
1
Saya cukup yakin newungkapan itu berasal dari Smalltalk. Ini juga digunakan di Ruby, dan kedua Objective-C dan Ruby mendapatkan banyak sintaks dan konvensi dari Smalltalk.
Brendon Roberto
3
Itu hanya memungkinkan untuk perubahan dalam alokasi. Dokumen secara eksplisit menyatakan -init akan dipanggil. Jadi itu lebih tergantung pada apakah Anda menimpa alokasi sebelumnya.
Kendall Helmstetter Gelner
7
Saya tidak bisa membayangkan mengapa solusi di mana Anda harus mengetik LEBIH akan lebih disukai (alokasi init), terutama dalam bahasa verbose seperti Objective-C di mana penghematan penekanan tombol akan menghemat waktu Anda. Mereka "pengembang Java mantap" hanya menggunakan keterampilan analitis mereka untuk menghabiskan lebih sedikit waktu menulis kode daripada mengetik karakter tambahan yang tidak perlu yang menghasilkan hasil fungsional yang sama.
DiscDev
9

Seringkali, Anda harus meneruskan argumen initdan karenanya Anda akan menggunakan metode yang berbeda, seperti [[SomeObject alloc] initWithString: @"Foo"]. Jika Anda terbiasa menulis ini, Anda terbiasa melakukannya dengan cara ini dan [[SomeObject alloc] init]mungkin akan lebih alami [SomeObject new].

Brian Campbell
sumber
7

Satu Jawaban Pendek adalah:

  1. Keduanya sama. Tapi
  2. 'baru' hanya berfungsi dengan inisialisasi dasar 'init', dan tidak akan bekerja dengan inisialisasi lainnya (misalnya initWithString :).
pengguna739711
sumber
3

Sebagai catatan, saya pribadi menggunakan [Foo new]jika saya ingin sesuatu di init dilakukan tanpa menggunakan nilai pengembaliannya di mana saja. Jika Anda tidak menggunakan pengembalian di [[Foo alloc] init]mana pun maka Anda akan mendapat peringatan. Lebih atau kurang, saya gunakan [Foo new]untuk permen mata.

evdude100
sumber
3

Saya sangat terlambat untuk ini tetapi saya ingin menyebutkan bahwa yang baru sebenarnya tidak aman di Obj-C dengan dunia Swift. Swift hanya akan membuat metode init default jika Anda tidak membuat inisialisasi lainnya. Memanggil baru di kelas cepat dengan penginisialisasi khusus akan menyebabkan crash. Jika Anda menggunakan mengalokasikan / init maka kompiler akan dengan benar mengeluh bahwa init tidak ada.

MurderDev
sumber
1

Jika baru melakukan pekerjaan untuk Anda, maka itu akan membuat kode Anda lebih kecil juga. Jika Anda akan memanggil [[SomeClass alloc] init]banyak tempat berbeda dalam kode Anda, Anda akan membuat Hot Spot dalam implementasi baru - yaitu, dalam runtc objc - yang akan mengurangi jumlah kesalahan cache Anda.

Dalam pemahaman saya, jika Anda perlu menggunakan penggunaan penginisialisasi kustom [[SomeClass alloc] initCustom].

Jika tidak, gunakan [SomeClass new].

Mike Crawford
sumber
1
Saya akan berdebat dengan "jika Anda perlu menggunakan inisialisasi kustom [[alokasi SomeClass] initCustom]". Jika Anda memerlukan penginisialisasi khusus tanpa parameter apa pun, jangan pernah melakukan sesuatu seperti yang Anda sarankan, cukup timpa initfungsi default , dan gunakan itu. [[SomeClass alloc] init];Jika Anda membutuhkan parameter, tetap tidak pernah melakukan sesuatu seperti itu, lakukan [[SomeClass alloc] initWith:...];. Terakhir, jika Anda mengganti initfungsi dengan implementasi kustom, Anda dapat memanggil newsaat membuat objek, dan itu masih akan memanggil initimplementasi kustom .
dirtydanee