本文的單例模式分為嚴格單例模式不嚴格單例模式。單例模式要求一個類有一個實例,有公開接口可以訪問這個實例。嚴格單例模式,要求一個類只有一個實例;不嚴格單例模式,可以創(chuàng)建多個實例。

有的類只能有一個實例,例如 UIApplication,通過 shared 屬性訪問唯一的實例,屬于嚴格單例模式。有用戶登錄功能的 App 中,如果當前用戶的數(shù)據(jù)模型與其他用戶的數(shù)據(jù)模型不同,那么當前用戶的類也應該用嚴格單例模式。在邏輯上,當前用戶只有一個,只能有一個實例;這樣可以在各個地方訪問當前用戶的數(shù)據(jù)。如果當前用戶的數(shù)據(jù)模型與其他用戶的數(shù)據(jù)模型相同,則應用不嚴格單例模式??梢越o其他用戶創(chuàng)建實例,同時也可以在各個地方訪問當前用戶的數(shù)據(jù)。

Swift 實現(xiàn)

嚴格單例模式

大多數(shù) 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
    }
}

靜態(tài)屬性 shared 持有唯一的實例,對外公開。

重載 init() 方法,使其對外不可見,不可以在外部調用,防止在外部創(chuàng)建實例。

重載 copy()、mutableCopy() 方法,返回 self,防止在外部復制實例。這里也可以返回 SingletonClass.shared,效果是一樣的,因為只有一個實例。只有 shared 能調用 copy()、mutableCopy() 方法,那么 self 就是 shared。寫 self,代碼比較簡潔。

單例一旦創(chuàng)建,一直持有,不能手動銷毀,但可以重置數(shù)據(jù)。如果需要的話,可以添加一個重置數(shù)據(jù)的方法 reset()。例如,當前用戶退出登錄,需要把當前用戶實例的所有屬性重置為默認值,防止數(shù)據(jù)錯誤。

不繼承自 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 去掉,即可創(chuàng)建多個實例。如果繼承自 NSObject,重載 copy()、mutableCopy() 方法:創(chuàng)建新實例,傳遞數(shù)據(jù)給新實例,返回新實例。其他與嚴格單例模式相同。

不嚴謹?shù)闹刂脭?shù)據(jù)方法

如果單例有很多屬性,重置數(shù)據(jù)需要把每個屬性都變成默認值,則 reset() 方法要寫很多。有一種不嚴謹?shù)闹刂脭?shù)據(jù)方法:重新生成一個實例并賦值給持有實例的靜態(tài)變量。

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 不是同一個對象。因此,這樣的重置數(shù)據(jù)方法不嚴謹。還是要老老實實把每個屬性賦為默認值。

Objective-C 實現(xiàn)

嚴格單例模式

.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

靜態(tài)變量 _shared 持有唯一的實例,通過 shared 方法對外公開。在這方法中,如果發(fā)現(xiàn) _shared 沒有初始化,則進行初始化。方法返回值的 nonnull 表示返回值不為空,這樣寫方便 Swift 調用。不加 nonnull,shared 方法在 Swift 中的返回值是 optional 類型 (SingletonClassOC?),不方便使用;加上 nonnull 則為 SingletonClassOC 類型。

重載 allocWithZone: 和 init 方法,由 dispath_once 保證父類方法只執(zhí)行一次并給 _shared 賦值,返回 _shared。外部調用初始化方法總是獲得 _shared 持有的唯一實例。

重載 copyWithZone: 和 mutableCopyWithZone: 方法,返回 self,防止在外部復制實例。由于只有一個實例 _shared,只能由 _shared 調用 copy、mutableCopy 方法,那么 self 就是 _shared。

如果需要,用 reset 方法重置數(shù)據(jù)。

不嚴格單例模式

.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 方法返回給外部訪問的實例。靜態(tài)變量 _shared 不需要被多個方法使用,因此寫在 shared 方法里即可。由 dispatch_once 保證 _shared 只初始化一次。

沒重載 allocWithZone: 和 init 方法,外部可以創(chuàng)建新實例。init 方法可以根據(jù)需要重載,在這里進行初始化參數(shù)等,和非單例模式的類一樣,調用父類方法,最后返回 self。

重載 copyWithZone: 和 mutableCopyWithZone: 方法,在里面創(chuàng)建新實例,傳遞數(shù)據(jù)給新實例,返回新實例。外部可以通過 copy 或 mutableCopy 方法復制實例。

SDWebImage 中就用到不嚴格單例模式

Android培訓,安卓培訓,手機開發(fā)培訓,移動開發(fā)培訓,云培訓培訓

NSObject 的類方法 new 相當于 alloc 和 init 方法。

轉載請注明出處:http://www.cnblogs.com/silence-cnblogs/p/6776217.html

http://www.cnblogs.com/silence-cnblogs/p/6776217.html