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

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

有的类只能有一个实例,例如 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.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

Swift、Objective-C 单例模式 (Singleton)的更多相关文章

  1. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  2. 【白话设计模式四】单例模式(Singleton)

    转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...

  3. ooad单例模式-Singleton

                                                单例模式Singleton 主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 比如建立目录 ...

  4. iOS单例模式(Singleton)写法简析

    单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模式的要点有三个:一是某个类只能有一个实例: ...

  5. 浅谈设计模式--单例模式(Singleton Pattern)

    题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...

  6. 设计模式之——单例模式(Singleton)的常见应用场景

    单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...

  7. 设计模式之单例模式(Singleton Pattern)

    单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...

  8. 设计模式(4) -- 单例模式(Singleton)

    设计模式(4)  -- 单例模式(Singleton) 试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说 ...

  9. IOS单例模式(Singleton)

    IOS单例模式(Singleton)   单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模 ...

随机推荐

  1. 优雅的使用sublime写lua~ sublime lua相关必装插件推荐~~

    缘起 lua脚本语言虽好,代码写得飞快,可是写错了调试起来却很困难,lua使用者经常容易犯得一个错误是--写错变量名了,if end 嵌套太多没匹配~,多打了一个逗号, 假设定义了一个变量 local ...

  2. Python的.py文件打包成exe可执行文件

    前几天做了几个简单的爬虫python程序,于是就想做个窗口看看效果. 首先是,窗口的话,以前没怎么接触过,就先考虑用Qt制作简单的ui.这里用前面sinanews的爬虫脚本为例,制作一个获取当天sin ...

  3. iOS网络编程笔记——Socket底层实现笔记

    Socket简单底层实现笔记: 以Socket客户端编程为例: 1.导入头文件 #import <arpa/inet.h> #import <netinet/in.h> #im ...

  4. Linux(CentOS6.7) 安装MySql5.7数据库

    linux(CentOS6.7) 环境Mysql 5.7.17安装教程分享给大家,供大家参考,具体内容如下: 1系统约定安装文件下载目录:/data/softwareMysql目录安装位置:/usr/ ...

  5. spdlog源码阅读 (1): sinks

    0. spdlog简单介绍 spdlog 是一个快速的 C++ 日志库,只包含头文件,兼容 C++11.项目地址 特性: 非常快 只包含头文件 无需依赖第三方库 支持跨平台 - Linux / Win ...

  6. Android知识点网址

    1.proguard字段详解 http://blog.csdn.net/jddkdd2/article/details/8858909 2.android提示框(时间,普通单选.多选对话框),常用控件 ...

  7. java根据HashMap中的值将其元素排序

    思路:HashMap或Map本身没有排序功能,若要进行较轻松的排序,可利用ArrayList中的sort方法 例子: import java.util.ArrayList; import java.u ...

  8. 输入输出流类iostream常用函数解析

    原创作品,转载请注明出处:http://www.cnblogs.com/shrimp-can/p/5657192.html 一.成员类型 1. ios::fmtflags: 格式标志,常用来设置输出的 ...

  9. Git修改提交注释

    修改本地最近一次已提交的注释 git commit --amend 如果已经上传到了github上,因此github的提交和已修改的提交不一样,推送到远程可以用下面命令强制修改 git push or ...

  10. static成员是可以被其所在class创建的实例访问!!!

    <span style="font-family: Arial, Helvetica, sans-serif; ">关于静态方法以及静态变量的使用就不详细的说了,我就这 ...