单例模式 与用dispatch_once实现例子
来源:互联网 发布:淘宝 app 官网 编辑:程序博客网 时间:2024/05/16 06:09
1.单例模式的定义。
单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中含有一个该类的静态私有对象,三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。
2.在Objective-C中,利用GCD实现单例。
尽管这是单例的实际定义,但在Foundation框架中不一定是这样。比如NSFileManger和NSNotificationCenter,分别通过它们的类方法defaultManager和defaultCenter获取。尽管不是严格意义的单例,这些类方法返回一个可以在应用的所有代码中访问到的类的共享实例。在本文中我们也会采用该方法。
使用Objective-C实现单例模式的最佳方式向来有很多争论,开发者(包括Apple在内)似乎每几年就会改变他们的想法。当Apple引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他们也引入了一个很适合用于实现单例模式的函数。
该函数就是dispatch_once:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
该函数接收一个dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型,实际上作为BOOL使用)。它还接收一个希望在应用的生命周期内仅被调度一次的代码块,对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如@synchronized之类的来防止使用多个线程或者队列时不同步的问题。
Apple的GCD Documentation证实了这一点:
如果被多个线程调用,该函数会同步等等直至代码块完成。
实际要如何使用这些呢?
好吧,假设有一个AccountManager类,你想在整个应用中访问该类的共享实例。你可以按如下代码简单实现一个类方法:
+ (AccountManager *)sharedManager {
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate; dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
这就意味着你任何时候访问共享实例,需要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。
该方法有很多优势:
1 线程安全
2 很好满足静态分析器要求
3 和自动引用计数(ARC)兼容
4 仅需要少量代码
该方法的劣势就是它仍然运行创建一个非共享的实例:
AccountManager *accountManager = [[AccountManager alloc] init];
有些时候你希望有这种行为,但如果正在想要的是仅一个实例被实例化就需要注意这点。
使用Objective-C实现单例模式的最佳方式向来有很多争论,开发者(包括Apple在内)似乎每几年就会改变他们的想法。当Apple引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他们也引入了一个很适合用于实现单例模式的函数。
该函数就是dispatch_once:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
该函数接收一个dispatch_once用于检查该代码块是否已经被调度的谓词(是一个长整型,实际上作为BOOL使用)。它还接收一个希望在应用的生命周期内仅被调度一次的代码块,对于本例就用于shared实例的实例化。
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如@synchronized之类的来防止使用多个线程或者队列时不同步的问题。
Apple的GCD Documentation证实了这一点:
如果被多个线程调用,该函数会同步等等直至代码块完成。
实际要如何使用这些呢?
好吧,假设有一个AccountManager类,你想在整个应用中访问该类的共享实例。你可以按如下代码简单实现一个类方法:
+ (AccountManager *)sharedManager {
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate; dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
这就意味着你任何时候访问共享实例,需要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。
该方法有很多优势:
1 线程安全
2 很好满足静态分析器要求
3 和自动引用计数(ARC)兼容
4 仅需要少量代码
该方法的劣势就是它仍然运行创建一个非共享的实例:
AccountManager *accountManager = [[AccountManager alloc] init];
有些时候你希望有这种行为,但如果正在想要的是仅一个实例被实例化就需要注意这点。
3.dispatch_once的实现分析
dispatch_once保证代码仅被执行一次,有两个参数,第一个参数
predicate
用来保证执行一次,第二个参数是要执行一次的任务block。dispatch_once_t的描述是typedef long dispatch_once_t;
dispatch_once展开是
~0l是数据类型为 long 的0 取反。
展开DISPATCH_EXPECT, 是__builtin_expect((x), (v)) ,__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间浪费,并没有改变其对真值的判断。
void
_dispatch_once(
dispatch_once_t
*predicate,
dispatch_block_t
block)
{
if
(DISPATCH_EXPECT(*predicate, ~
0l
) != ~
0l
) {
dispatch_once(predicate, block);
}
}
#define dispatch_once _dispatch_once
展开DISPATCH_EXPECT, 是__builtin_expect((x), (v)) ,__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间浪费,并没有改变其对真值的判断。
内容主要转自:http://www.cnblogs.com/hellocby/archive/2012/08/24/2654488.html 以及百度百科。
0 0
- 单例模式 与用dispatch_once实现例子
- 用dispatch_once实现单例模式
- 使用dispatch_once实现单例模式
- 使用dispatch_once实现单例模式
- GCD---dispatch_once实现单例模式
- dispatch_once 单例模式
- dispatch_once 实现单例
- dispatch_once 实现单例
- dispatch_once 实现单例
- [Objective-C] 用 dispatch_once 实现单例
- dispatch_once创建单例模式
- 使用dispatch_once实现单例
- 单例模式的实现与例子。
- iOS开发单例模式 dispatch_once
- iOS开发单例模式 dispatch_once
- iOS 的单例模式 dispatch_once
- iOS开发单例模式 dispatch_once
- iOS开发单例模式 dispatch_once
- ZLL协议的常见问题
- 拥抱开源——Linux C/C++程序员必须熟悉的开源项目
- CodeForcesGym 100733D Little thief Shi
- Python学习笔记(3)range的用法
- leetcode笔记:Minimum Path Sum
- 单例模式 与用dispatch_once实现例子
- ApplicationContext的三种实现方式以及在web.xml配置的两种方式
- 经典SQL语句大全
- 如何从官网下载Chrome浏览器离线安装包
- 浅析Linux计算机进程地址空间与内核装载ELF
- volatile的详细讲解
- Java动态代理机制
- 虚拟机中伪分布式Hadoop的部署
- Linux 学习(3)-- kernel版本号的修改