本文的單例模式分爲嚴格單例模式和不嚴格單例模式。單例模式要求一個類有一個實例,有公開接口能夠訪問這個實例。嚴格單例模式,要求一個類只有一個實例;不嚴格單例模式,能夠建立多個實例。html
有的類只能有一個實例,例如 UIApplication,經過 shared 屬性訪問惟一的實例,屬於嚴格單例模式。有用戶登陸功能的 App 中,若是當前用戶的數據模型與其餘用戶的數據模型不一樣,那麼當前用戶的類也應該用嚴格單例模式。在邏輯上,當前用戶只有一個,只能有一個實例;這樣能夠在各個地方訪問當前用戶的數據。若是當前用戶的數據模型與其餘用戶的數據模型相同,則應用不嚴格單例模式。能夠給其餘用戶建立實例,同時也能夠在各個地方訪問當前用戶的數據。objective-c
大多數 Objective-C 的類都繼承自 NSObject,而 Swift 的類能夠繼承自 NSObject 或者不繼承。swift
class SingletonClass: NSObject { static let shared = SingletonClass() // Make sure the class has only one instance // Should not init or copy outside private override init() {} override func copy() -> Any { return self // SingletonClass.shared } override func mutableCopy() -> Any { return self // SingletonClass.shared } // Optional func reset() { // Reset all properties to default value } }
靜態屬性 shared 持有惟一的實例,對外公開。ide
重載 init() 方法,使其對外不可見,不能夠在外部調用,防止在外部建立實例。this
重載 copy()、mutableCopy() 方法,返回 self,防止在外部複製實例。這裏也能夠返回 SingletonClass.shared,效果是同樣的,由於只有一個實例。只有 shared 能調用 copy()、mutableCopy() 方法,那麼 self 就是 shared。寫 self,代碼比較簡潔。spa
單例一旦建立,一直持有,不能手動銷燬,但能夠重置數據。若是須要的話,能夠添加一個重置數據的方法 reset()。例如,當前用戶退出登陸,須要把當前用戶實例的全部屬性重置爲默認值,防止數據錯誤。code
class SingletonClass2 { static let shared = SingletonClass2() // Make sure the class has only one instance // Should not init outside private init() {} // Optional func reset() { // Reset all properties to default value } }
不繼承自 NSObject 的類沒有 copy()、mutableCopy() 方法,不須要重載。其餘同上。htm
把重載的 init() 方法去掉,或者把 private 去掉,便可建立多個實例。若是繼承自 NSObject,重載 copy()、mutableCopy() 方法:建立新實例,傳遞數據給新實例,返回新實例。其餘與嚴格單例模式相同。對象
若是單例有不少屬性,重置數據須要把每一個屬性都變成默認值,則 reset() 方法要寫不少。有一種不嚴謹的重置數據方法:從新生成一個實例並賦值給持有實例的靜態變量。blog
class SingletonClass3 { private static var _shared = SingletonClass3() static var shared: SingletonClass3 { return _shared } private init() {} // Not safe // We can obtain more than one instance outside with this function func reset() { SingletonClass3._shared = SingletonClass3() } }
若是在外部訪問單例都經過 shared 屬性,這麼寫不會出錯。然而,若是外部持有單例,就有可能出錯。
let s = SingletonClass3.shared s.reset() print(s === SingletonClass3.shared) // false
以上會輸出 false,s 在重置以後,和 SingletonClass3.shared 不是同一個對象。所以,這樣的重置數據方法不嚴謹。仍是要老老實實把每一個屬性賦爲默認值。
.h 文件
@interface SingletonClassOC : NSObject + (nonnull instancetype)shared; + (instancetype)new NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE; - (id)copy NS_UNAVAILABLE; - (id)mutableCopy NS_UNAVAILABLE; @end
.m 文件
@implementation SingletonClassOC + (nonnull instancetype)shared { static id _shared; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _shared = [[self alloc] init]; }); return _shared; } // Optional - (void)reset { // Reset all properties to default value } @end
在 .h 文件中,用 NS_UNAVAILABLE 禁用初始化和拷貝方法,只容許用過 shared 方法訪問惟一實例。
靜態變量 _shared 持有惟一的實例,經過 shared 方法對外公開。由 dispatch_once 保證 _shared 只初始化一次。方法返回值的 nonnull 表示返回值不爲空,這樣寫方便 Swift 調用。不加 nonnull,shared 方法在 Swift 中的返回值是 optional 類型 (SingletonClassOC?),不方便使用;加上 nonnull 則爲 SingletonClassOC 類型。
若是須要,用 reset 方法重置數據。
.h 文件
@interface SingletonClassOC2 : NSObject + (nonnull instancetype)shared; @end
.m 文件
@implementation SingletonClassOC2 + (nonnull instancetype)shared { static id _shared; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _shared = [[self alloc] init]; }); return _shared; } - (id)copyWithZone:(NSZone *)zone { SingletonClassOC2 *copiedObject = [[self.class allocWithZone:zone] init]; // Copy data to copiedObject return copiedObject; } - (id)mutableCopyWithZone:(NSZone *)zone { SingletonClassOC2 *copiedObject = [[self.class allocWithZone:zone] init]; // Copy data to copiedObject return copiedObject; } - (void)reset { // Reset all properties to default value } @end
公開的 shared 方法與嚴格單例模式相同。外部能夠經過 init 方法建立與 _shared 不一樣的實例。
重載 copyWithZone: 和 mutableCopyWithZone: 方法,在裏面建立新實例,傳遞數據給新實例,返回新實例。外部能夠經過 copy 或 mutableCopy 方法複製實例。
SDWebImage 中就用到不嚴格單例模式
NSObject 的類方法 new 至關於 alloc 和 init 方法。
轉載請註明出處:http://www.cnblogs.com/silence-cnblogs/p/6776217.html