標籤:傳遞 可見 print turn data func init uri 資料模型
本文的單例模式分為嚴格單例模式和不嚴格單例模式。單例模式要求一個類有一個執行個體,有公開介面可以訪問這個執行個體。嚴格單例模式,要求一個類只有一個執行個體;不嚴格單例模式,可以建立多個執行個體。
有的類只能有一個執行個體,例如 UIApplication,通過 shared 屬性訪問唯一的執行個體,屬於嚴格單例模式。有使用者登入功能的 App 中,如果目前使用者的資料模型與其他使用者的資料模型不同,那麼目前使用者的類也應該用嚴格單例模式。在邏輯上,目前使用者只有一個,只能有一個執行個體;這樣可以在各個地方訪問目前使用者的資料。如果目前使用者的資料模型與其他使用者的資料模型相同,則應用不嚴格單例模式。可以給其他使用者建立執行個體,同時也可以在各個地方訪問目前使用者的資料。
Swift 實現嚴格單例模式
大多數 Objective-C 的類都繼承自 NSObject,而 Swift 的類可以繼承自 NSObject 或者不繼承。
繼承自 NSObject
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 持有唯一的執行個體,對外公開。
重載 init() 方法,使其對外不可見,不可以在外部調用,防止在外部建立執行個體。
重載 copy()、mutableCopy() 方法,返回 self,防止在外部複製執行個體。這裡也可以返回 SingletonClass.shared,效果是一樣的,因為只有一個執行個體。只有 shared 能調用 copy()、mutableCopy() 方法,那麼 self 就是 shared。寫 self,代碼比較簡潔。
單例一旦建立,一直持有,不能手動銷毀,但可以重設資料。如果需要的話,可以添加一個重設資料的方法 reset()。例如,目前使用者退出登入,需要把目前使用者執行個體的所有屬性重設為預設值,防止資料錯誤。
不繼承自 NSObject
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() 方法,不需要重載。其他同上。
不嚴格單例模式
把重載的 init() 方法去掉,或者把 private 去掉,即可建立多個執行個體。如果繼承自 NSObject,重載 copy()、mutableCopy() 方法:建立新執行個體,傳遞資料給新執行個體,返回新執行個體。其他與嚴格單例模式相同。
不嚴謹的重設資料方法
如果單例有很多屬性,重設資料需要把每個屬性都變成預設值,則 reset() 方法要寫很多。有一種不嚴謹的重設資料方法:重建一個執行個體並賦值給持有執行個體的靜態變數。
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.shareds.reset()print(s === SingletonClass3.shared) // false
以上會輸出 false,s 在重設之後,和 SingletonClass3.shared 不是同一個對象。因此,這樣的重設資料方法不嚴謹。還是要老老實實把每個屬性賦為預設值。
Objective-C 實現嚴格單例模式
.h 檔案
@interface SingletonClassOC : NSObject+ (nonnull instancetype)shared;@end
.m 檔案
@implementation SingletonClassOCstatic id _shared;+ (nonnull instancetype)shared { if (!_shared) { _shared = [[self alloc] init]; } return _shared;}+ (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _shared = [super allocWithZone:zone]; }); return _shared;}- (instancetype)init { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _shared = [super init]; }); return _shared;}- (id)copyWithZone:(NSZone *)zone { return self; // _shared}- (id)mutableCopyWithZone:(NSZone *)zone { return self; // _shared}// Optional- (void)reset { // Reset all properties to default value}@end
靜態變數 _shared 持有唯一的執行個體,通過 shared 方法對外公開。在這方法中,如果發現 _shared 沒有初始化,則進行初始化。方法傳回值的 nonnull 表示傳回值不為空白,這樣寫方便 Swift 調用。不加 nonnull,shared 方法在 Swift 中的傳回值是 optional 類型 (SingletonClassOC?),不方便使用;加上 nonnull 則為 SingletonClassOC 類型。
重載 allocWithZone: 和 init 方法,由 dispath_once 保證父類方法只執行一次並給 _shared 賦值,返回 _shared。外部調用初始化方法總是獲得 _shared 持有的唯一執行個體。
重載 copyWithZone: 和 mutableCopyWithZone: 方法,返回 self,防止在外部複製執行個體。由於只有一個執行個體 _shared,只能由 _shared 調用 copy、mutableCopy 方法,那麼 self 就是 _shared。
如果需要,用 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 方法返回給外部存取的執行個體。靜態變數 _shared 不需要被多個方法使用,因此寫在 shared 方法裡即可。由 dispatch_once 保證 _shared 只初始化一次。
沒重載 allocWithZone: 和 init 方法,外部可以建立新執行個體。init 方法可以根據需要重載,在這裡進行初始化參數等,和非單例模式的類一樣,調用父類方法,最後返回 self。
重載 copyWithZone: 和 mutableCopyWithZone: 方法,在裡面建立新執行個體,傳遞資料給新執行個體,返回新執行個體。外部可以通過 copy 或 mutableCopy 方法複製執行個體。
SDWebImage 中就用到不嚴格單例模式
NSObject 的類方法 new 相當於 alloc 和 init 方法。
轉載請註明出處:http://www.cnblogs.com/silence-cnblogs/p/6776217.html
Swift、Objective-C 單例模式 (Singleton)