Swift、Objective-C 单例模式 (Singleton)
来源:互联网 发布:怎么注册网络域名 编辑:程序博客网 时间:2024/05/21 22:51
本文的单例模式分为严格单例模式和不严格单例模式。单例模式要求一个类有一个实例,有公开接口可以访问这个实例。严格单例模式,要求一个类只有一个实例;不严格单例模式,可以创建多个实例。
有的类只能有一个实例,例如 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 中就用到不严格单例模式
- Swift、Objective-C 单例模式 (Singleton)
- Objective C 实现Singleton(单例)模式.
- Objective —C 单例模式 Singleton
- Objective-C使用单例(Singleton)模式
- Objective-C中的单例模式(singleton)
- Objective —C 的单例模式 Singleton实现
- Objective-C的单例模式(singleton)
- Objective-C的单例模式(singleton)
- objective-c 单例模式Singleton的实现
- Objective-C的单例模式(singleton)
- Objective-C的单例模式(singleton)
- Objective-c 单例设计模式(Singleton)
- Objective-C 中singleton(单例模式)的实现
- Objective C 的单例模式 Singleton with ARC
- Objective-C 中singleton(单例模式)的实现
- Objective-C 单例模式singleton(参考apple官方例子)
- Swift设计模式之单例(SINGLETON)
- c++-单例模式Singleton
- 通过babel-register在nodejs端使用es6
- 创建数据库
- 使用sqlplus 登陆数据库
- oracle数据库关闭与启动
- Linux 软件包管理简介
- Swift、Objective-C 单例模式 (Singleton)
- 使用NRM 管理NPM源
- oracle spool 用法
- nodejs 使用uuid
- oracle 导入csv文件
- mybatis大于小于的转义
- Unity GameObject.activeSelf, GameObject.activeInHierarchy,GameObject.SetActive和SetActiveRecursively
- tensorflow获取可用GPU设备
- Java 命名约定