Jika Anda dapat menargetkan iOS 4.0 atau lebih tinggi
Menggunakan GCD, apakah ini cara terbaik untuk membuat singleton di Objective-C (thread safe)?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
instancetype
. Kelengkapan kode jauh lebih baik saat menggunakan itu daripadaid
.Jawaban:
Ini adalah cara yang bisa diterima dan aman untuk membuat instance kelas Anda. Secara teknis mungkin bukan "singleton" (dalam hal itu hanya ada 1 objek), tetapi selama Anda hanya menggunakan
[Foo sharedFoo]
metode untuk mengakses objek, ini cukup baik.sumber
jenis instancet
instancetype
hanyalah salah satu dari banyak ekstensi bahasaObjective-C
, dengan lebih banyak ditambahkan dengan setiap rilis baru.Ketahuilah, menyukainya.
Dan anggap sebagai contoh bagaimana memperhatikan detail tingkat rendah dapat memberi Anda wawasan tentang cara-cara baru yang kuat untuk mengubah Objective-C.
Rujuk di sini: tipe instancet
sumber
MySingleton.h
MySingleton.m
sumber
init
?MySingleton
, misalnya dalamMySingleton.m
panggilan saya[super alloc]
Anda dapat menghindari bahwa kelas dialokasikan dengan menimpa metode alokasi.
sumber
Dave benar, itu baik-baik saja. Anda mungkin ingin memeriksa dokumen Apple tentang cara membuat singleton untuk kiat menerapkan beberapa metode lain untuk memastikan bahwa hanya satu yang dapat dibuat jika kelas memilih TIDAK untuk menggunakan metode sharedFoo.
sumber
Jika Anda ingin memastikan bahwa [[alokasi MyClass] init] mengembalikan objek yang sama dengan sharedInstance (tidak diperlukan menurut pendapat saya, tetapi beberapa orang menginginkannya), itu dapat dilakukan dengan sangat mudah dan aman menggunakan dispatch_once kedua:
Ini memungkinkan setiap kombinasi [[alokasi MyClass] init] dan [MyClass sharedInstance] untuk mengembalikan objek yang sama; [MyClass sharedInstance] hanya akan sedikit lebih efisien. Cara kerjanya: [MyClass sharedInstance] akan memanggil [[alokasi MyClass] init] sekali. Kode lain bisa memanggilnya juga, berapa kali. Penelepon pertama ke init akan melakukan inisialisasi "normal" dan menyimpan objek tunggal dalam metode init. Setiap panggilan selanjutnya ke init akan sepenuhnya mengabaikan alokasi apa yang dikembalikan dan mengembalikan Instansi yang sama; hasil alokasi akan dibatalkan alokasi.
Metode + sharedInstance akan berfungsi seperti biasa. Jika itu bukan penelepon pertama yang memanggil [[alokasi MyClass] init], maka hasil dari init bukanlah hasil dari panggilan alokasi, tetapi itu OK.
sumber
Anda bertanya apakah ini "cara terbaik untuk membuat singleton".
Beberapa pemikiran:
Pertama, ya, ini adalah solusi yang aman.
dispatch_once
Pola ini adalah cara modern yang aman untuk menghasilkan lajang di Objective-C. Jangan khawatir di sana.Namun Anda bertanya, apakah ini cara "terbaik" untuk melakukannya. Orang harus mengakui, bahwa,
instancetype
dan[[self alloc] init]
berpotensi menyesatkan ketika digunakan bersama dengan lajang.Keuntungannya
instancetype
adalah bahwa ini adalah cara yang tidak ambigu untuk menyatakan bahwa kelas dapat subkelas tanpa menggunakan jenisid
, seperti yang harus kita lakukan di masa lalu.Tetapi
static
dalam metode ini menyajikan tantangan subclassing. Bagaimana jikaImageCache
danBlobCache
lajang keduanya subclass dariCache
superclass tanpa menerapkansharedCache
metode mereka sendiri ?Agar ini berfungsi, Anda harus memastikan subclass mengimplementasikan
sharedInstance
metode mereka sendiri (atau apa pun namanya untuk kelas Anda).Intinya, sumber asli Anda
sharedInstance
sepertinya akan mendukung subclass, tetapi tidak. Jika Anda bermaksud mendukung subclassing, paling tidak sertakan dokumentasi yang memperingatkan pengembang masa depan bahwa mereka harus mengganti metode ini.Untuk interoperabilitas terbaik dengan Swift, Anda mungkin ingin mendefinisikan ini sebagai properti, bukan metode kelas, misalnya:
Kemudian Anda dapat melanjutkan dan menulis getter untuk properti ini (implementasinya akan menggunakan
dispatch_once
pola yang Anda sarankan):Manfaatnya adalah jika pengguna Swift menggunakannya, mereka akan melakukan sesuatu seperti:
Catatan, tidak ada
()
, karena kami menerapkannya sebagai properti. Mulai Swift 3, beginilah cara lajang umumnya diakses. Jadi mendefinisikannya sebagai properti membantu memfasilitasi interoperabilitas itu.Sebagai tambahan, jika Anda melihat bagaimana Apple mendefinisikan lajang mereka, ini adalah pola yang telah mereka adopsi, misalnya
NSURLSession
lajang mereka didefinisikan sebagai berikut:Pertimbangan interoperabilitas Swift yang sangat kecil adalah nama singleton. Lebih baik jika Anda dapat memasukkan nama tipe, daripada
sharedInstance
. Misalnya, jika kelasnya adalahFoo
, Anda mungkin mendefinisikan properti singleton sebagaisharedFoo
. Atau jika kelasnya adalahDatabaseManager
, Anda dapat menghubungi propertisharedManager
. Kemudian pengguna Swift dapat melakukan:Jelas, jika Anda benar-benar ingin menggunakan
sharedInstance
, Anda selalu dapat mendeklarasikan nama Swift jika Anda ingin:Jelas, ketika menulis kode Objective-C, kita seharusnya tidak membiarkan interoperabilitas Swift lebih besar daripada pertimbangan desain lainnya, tetapi tetap saja, jika kita dapat menulis kode yang dengan anggun mendukung kedua bahasa, itu lebih disukai.
Saya setuju dengan orang lain yang menunjukkan bahwa jika Anda ingin ini menjadi singleton sejati di mana pengembang tidak dapat / tidak seharusnya (secara tidak sengaja) membuat instantiate instance mereka sendiri,
unavailable
kualifikasiinit
dannew
bijaksana.sumber
Untuk membuat thread safe singleton, Anda dapat melakukannya seperti ini:
dan blog ini menjelaskan singleton dengan sangat baik di objc / cocoa
sumber
sumber
sumber