Anda bertanya apakah ini "cara terbaik untuk membuat singleton".
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 jenis id
, seperti yang harus kita lakukan di masa lalu.
Tetapi static
dalam metode ini menyajikan tantangan subclassing. Bagaimana jika ImageCache
dan BlobCache
lajang keduanya subclass dari Cache
superclass tanpa menerapkan sharedCache
metode mereka sendiri ?
ImageCache *imageCache = [ImageCache sharedCache]; // fine
BlobCache *blobCache = [BlobCache sharedCache]; // error; this will return the aforementioned ImageCache!!!
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:
@interface Foo : NSObject
@property (class, readonly, strong) Foo *sharedFoo;
@end
Kemudian Anda dapat melanjutkan dan menulis getter untuk properti ini (implementasinya akan menggunakan dispatch_once
pola yang Anda sarankan):
+ (Foo *)sharedFoo { ... }
Manfaatnya adalah jika pengguna Swift menggunakannya, mereka akan melakukan sesuatu seperti:
let foo = Foo.shared
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:
@property (class, readonly, strong) NSURLSession *sharedSession;
Pertimbangan interoperabilitas Swift yang sangat kecil adalah nama singleton. Lebih baik jika Anda dapat memasukkan nama tipe, daripada sharedInstance
. Misalnya, jika kelasnya adalah Foo
, Anda mungkin mendefinisikan properti singleton sebagai sharedFoo
. Atau jika kelasnya adalah DatabaseManager
, Anda dapat menghubungi properti sharedManager
. Kemudian pengguna Swift dapat melakukan:
let foo = Foo.shared
let manager = DatabaseManager.shared
Jelas, jika Anda benar-benar ingin menggunakan sharedInstance
, Anda selalu dapat mendeklarasikan nama Swift jika Anda ingin:
@property (class, readonly, strong) Foo* sharedInstance NS_SWIFT_NAME(shared);
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
kualifikasi init
dan new
bijaksana.