Swift、Objective-C 单例模式 (Singleton)

Swift、Objective-C 单例模式 (Singleton)

本文的单例模式分为严格单例模式不严格单例模式。单例模式要求一个类有一个实例,有公开接口能够访问这个实例。严格单例模式,要求一个类只有一个实例;不严格单例模式,能够建立多个实例。html

有的类只能有一个实例,例如 UIApplication,经过 shared 属性访问惟一的实例,属于严格单例模式。有用户登陆功能的 App 中,若是当前用户的数据模型与其余用户的数据模型不一样,那么当前用户的类也应该用严格单例模式。在逻辑上,当前用户只有一个,只能有一个实例;这样能够在各个地方访问当前用户的数据。若是当前用户的数据模型与其余用户的数据模型相同,则应用不严格单例模式。能够给其余用户建立实例,同时也能够在各个地方访问当前用户的数据。objective-c

Swift 实现

严格单例模式

大多数 Objective-C 的类都继承自 NSObject,而 Swift 的类能够继承自 NSObject 或者不继承。swift

继承自 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 持有惟一的实例,对外公开。ide

重载 init() 方法,使其对外不可见,不能够在外部调用,防止在外部建立实例。this

重载 copy()、mutableCopy() 方法,返回 self,防止在外部复制实例。这里也能够返回 SingletonClass.shared,效果是同样的,由于只有一个实例。只有 shared 能调用 copy()、mutableCopy() 方法,那么 self 就是 shared。写 self,代码比较简洁。spa

单例一旦建立,一直持有,不能手动销毁,但能够重置数据。若是须要的话,能够添加一个重置数据的方法 reset()。例如,当前用户退出登陆,须要把当前用户实例的全部属性重置为默认值,防止数据错误。code

不继承自 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() 方法,不须要重载。其余同上。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 不是同一个对象。所以,这样的重置数据方法不严谨。仍是要老老实实把每一个属性赋为默认值。

Objective-C 实现

严格单例模式

.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

相关文章
相关标签/搜索