單例模式要求一個(gè)類有一個(gè)實(shí)例,有公開(kāi)接口可以訪問(wèn)這個(gè)實(shí)例。單例模式分為以下兩種模式:
-
嚴(yán)格單例模式
嚴(yán)格單例模式,要求一個(gè)類只有一個(gè)實(shí)例。
-
不嚴(yán)格單例模式
不嚴(yán)格單例模式,可以創(chuàng)建多個(gè)實(shí)例。
有的類只能有一個(gè)實(shí)例,例如 UIApplication
類,通過(guò) shared
屬性訪問(wèn)唯一的實(shí)例,屬于嚴(yán)格單例模式。廢話不多說(shuō),接下來(lái)看看 Swift 和 Objective-C 的每種單例模式的具體實(shí)現(xiàn)。
Swift 實(shí)現(xiàn)
嚴(yán)格單例模式
大多數(shù) Objective-C 的類都繼承自 NSObject,而 Swift 的類可以繼承自 NSObject 類或者不繼承。
- 繼承自 NSObject 類
- 寫法一
open class DYFStore: NSObject {
public static let `default` = DYFStore()
/// Overrides default constructor.
private override init() {
super.init()
}
/// Make sure the class has only one instance.
open override func copy() -> Any {
return self
}
/// Make sure the class has only one instance.
open override func mutableCopy() -> Any {
return self
}
}
2.寫法二
open class DYFStore: NSObject {
/// A struct named "Inner".
private struct Inner {
static var instance: DYFStore? = nil
}
public class var `default`: DYFStore {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
guard let instance = Inner.instance else {
let store = DYFStore()
Inner.instance = store
return store
}
return instance
}
/// Overrides default constructor.
private override init() {
super.init()
}
/// Make sure the class has only one instance.
open override func copy() -> Any {
return self
}
/// Make sure the class has only one instance.
open override func mutableCopy() -> Any {
return self
}
}
- 寫法三
open class DYFStore: NSObject {
/// A struct named "Inner".
private struct Inner {
static var instance: DYFStore? = nil
}
public class var `default`: DYFStore {
DispatchQueue.once(token: "com.storekit.DYFStore") {
if Inner.instance == nil {
Inner.instance = DYFStore()
}
}
return Inner.instance!
}
/// Constructs a store singleton with class method.
///
/// - Returns: A store singleton.
public class func defaultStore() -> DYFStore {
return DYFStore.self.default
}
/// Overrides default constructor.
private override init() {
super.init()
}
/// Make sure the class has only one instance.
open override func copy() -> Any {
return self
}
/// Make sure the class has only one instance.
open override func mutableCopy() -> Any {
return self
}
}
// MARK: - Extends the properties and method for the dispatch queue.
extension DispatchQueue {
/// Declares an array of string to record the token.
private static var _onceTracker = [String]()
/// Executes a block of code associated with a given token, only once. The code is thread safe and will only execute the code once even in the presence of multi-thread calls.
///
/// - Parameters:
/// - token: A unique idetifier.
/// - block: A block to execute once.
public class func once(token: String, block: () -> Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
/// Submits a task to a dispatch queue for asynchronous execution.
///
/// - Parameter block: The block to be invoked on the queue.
public func asyncTask(block: @escaping () -> Void) {
self.async(execute: block)
}
/// Submits a task to a dispatch queue for asynchronous execution after a specified time.
///
/// - Parameters:
/// - time: The block should be executed after a few time delay.
/// - block: The block to be invoked on the queue.
public func asyncAfter(delay time: Double, block: @escaping () -> Void) {
self.asyncAfter(deadline: .now() + time, execute: block)
}
}
DYFStore (In-App Purchase in Swift for iOS) 屬性 default 持有唯一的實(shí)例,對(duì)外公開(kāi)。
重載 init() 方法,使其對(duì)外不可見(jiàn),不可以在外部調(diào)用,防止在外部創(chuàng)建實(shí)例。
重載 copy()、mutableCopy() 方法,返回 self,防止在外部復(fù)制實(shí)例。這里也可以返回 DYFStore.default,效果是一樣的,因?yàn)橹挥幸粋€(gè)實(shí)例。只有屬性 default 能調(diào)用 copy()、mutableCopy() 方法,那么 self 就是屬性 default。寫 self,代碼比較簡(jiǎn)潔。
- 不繼承自 NSObject 類
open class DYFStore {
public class let `default` = DYFStore()
/// Privatizes default constructor.
private init() {}
}
不繼承自 NSObject 的類沒(méi)有 copy()、mutableCopy() 方法,不需要重載。其他同上。
不嚴(yán)格單例模式
把重載的 init() 方法去掉,或者把 private 去掉,即可創(chuàng)建多個(gè)實(shí)例。如果繼承自 NSObject,重載 copy()、mutableCopy() 方法:創(chuàng)建新實(shí)例,傳遞數(shù)據(jù)給新實(shí)例,返回新實(shí)例。其他與嚴(yán)格單例模式相同。
open class DYFStore {
public static let `default` = DYFStore()
init() {}
}
Objective-C 實(shí)現(xiàn)
Objective-C 創(chuàng)建對(duì)象的步驟分為以下兩步:
- 1、申請(qǐng)內(nèi)存(alloc)
- 2、初始化(init)
我們要確保對(duì)象的唯一性,因此在第一步階段時(shí)我們就要攔截它。
當(dāng)調(diào)用 alloc 方法時(shí),OC 內(nèi)部會(huì)調(diào)用 allocWithZone 方法來(lái)申請(qǐng)內(nèi)存,我們覆寫這個(gè)方法,然后在這個(gè)方法中賦值 _instance 并返回單例對(duì)象,這樣就可以達(dá)到我們的目的。
拷貝對(duì)象也是同樣的原理,覆寫copyWithZone方法,然后在這個(gè)方法中調(diào)用 _instance 返回單例對(duì)象,或者禁用 copy 和 mutableCopy 方法 。
嚴(yán)格單例模式
.h 文件
@interface DYFStore : NSObject
/** Constructs a store singleton with class method.
@return A store singleton.
*/
+ (instancetype)defaultStore;
/** Disable this method to make sure the class has only one instance.
*/
+ (instancetype)new NS_UNAVAILABLE;
/** Disable this method to make sure the class has only one instance.
*/
- (id)copy NS_UNAVAILABLE;
/** Disable this method to make sure the class has only one instance.
*/
- (id)mutableCopy NS_UNAVAILABLE;
@end
.m 文件
@implementation DYFStore
// Provides a global static variable.
static DYFStore *_instance = nil;
+ (instancetype)defaultStore {
return [[self.class alloc] init];
}
/** Returns a new instance of the receiving class.
*/
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
}
return _instance;
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super init];
[_instance setup];
});
return _instance;
}
/** Sets initial value for some member variables.
*/
- (void)setup {
}
@end
在 .h 文件中,用 NS_UNAVAILABLE 禁用初始化和拷貝方法,只允許用 defaultStore 方法訪問(wèn)唯一實(shí)例。
靜態(tài)變量 _instance 持有唯一的實(shí)例,通過(guò) defaultStore 方法對(duì)外公開(kāi)。由 dispatch_once 保證 _instance 只初始化一次。方法返回值的 nonnull 表示返回值不為空,這樣寫方便 Swift 調(diào)用。不加 nonnull,defaultStore 方法在 Swift 中的返回值是 optional 類型 (DYFStore?),不方便使用;若加上 nonnull,則為 DYFStore (In-App Purchase in Objective-C for iOS) 類型。
NSObject 的類方法 new 相當(dāng)于 alloc 和 init 方法。
不嚴(yán)格單例模式
.h 文件
@interface DYFStore : NSObject
/** Constructs a store singleton with class method.
@return A store singleton.
*/
+ (instancetype)defaultStore;
@end
.m 文件
@implementation DYFStore
+ (instancetype)defaultStore {
static DYFStore *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
@end
公開(kāi)的 defaultStore 方法與嚴(yán)格單例模式相同。外部可以通過(guò) init 方法創(chuàng)建與 _instance 不同的實(shí)例。
如果重載 copyWithZone: 和 mutableCopyWithZone: 方法,就在里面創(chuàng)建新實(shí)例,傳遞數(shù)據(jù)給新實(shí)例,返回新實(shí)例。外部可以通過(guò) copy 或 mutableCopy 方法復(fù)制實(shí)例。
- (id)copyWithZone:(NSZone *)zone {
DYFStore *store = [[self.class allocWithZone:zone] init];
// Copy data to store
return store;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
DYFStore *store = [[self.class allocWithZone:zone] init];
// Copy data to store
return store;
}
總結(jié):
寫的有不好的地方希望大家指出,我會(huì)更正,大家有什么看不明白的,也可以在評(píng)論里面提問(wèn),我會(huì)盡力解答。
點(diǎn)贊+關(guān)注,第一時(shí)間獲取技術(shù)干貨和最新知識(shí)點(diǎn),謝謝你的支持!
最后祝大家生活愉快~