内容简介:单例是一种常见的设计模式。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。在单例所属的类中只存在这么一个实例,并且类似全局变量,在系统任意位置都能访问单例对象。1)在系统中某种对象只能存在一个,多了不行。
1:概念
单例是一种常见的设计模式。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
在单例所属的类中只存在这么一个实例,并且类似全局变量,在系统任意位置都能访问单例对象。
2:用处
1)在系统中某种对象只能存在一个,多了不行。
2)系统中某种对象实例只需要一个就够了,节省内存。
3:iOS系统中一些用到单例的地方
[UIApplication sharedApplication]; [NSNotificationCenter defaultCenter]; [NSFileManager defaultManager]; [NSUserDefaults standardUserDefaults]; [NSURLCache sharedURLCache]; [NSHTTPCookieStorage sharedHTTPCookieStorage];复制代码
iOS单例的创建
1.单线程单例
我们知道对于 单例类
,我们必须留出一个接口来返回生成的单例,由于一个类中只能有一个实例,所以我们在第一次访问这个实例的时候创建,之后访问直接取已经创建好的实例
@implementation Singleton + (instancetype)shareInstance { static Singleton* single; if (!single) { single = [[Singleton alloc] init]; } return single; } @end 复制代码
ps:严格意义上来说,我们还需要将 alloc
方法封住,因为严格的单例是不允许再创建其他实例的,而 alloc
方法可以在外部任意生成实例。但是考虑到 alloc
属于NSObject,iOS中无法将 alloc
变成私有方法,最多只能覆盖 alloc
让其返回空,不过这样做也可能会让使用接口的人误解,造成其他问题。所以我们一般情况下对 alloc
不做特殊处理。系统的单例也未对 alloc
做任何处理
2.@synchronized单例
对于一个实例,我们一般并不能保证他一定会在单线程模式下使用,所以我们得适配多线程情况。在多线程情况下,上面的单例创建方式可能会出现问题。如果两个线程同时调用 shareInstance
,可能会创建出2个single来。所以对于多线程情况下,我们需要使用 @synchronized
来加锁。
@implementation Singleton + (instancetype)shareInstance { static Singleton* single; @synchronized(self){ if (!single) { single = [[Singleton alloc] init]; } } return single; } @end 复制代码
这样的话,当多个线程同时调用 shareInstance
时,由于 @synchronized
已经加锁,所以只能有一个线程进入创建 single
。这样就解决了多线程下调用单例的问题
3.dispatch_once单例
使用 @synchronized
虽然解决了多线程的问题,但是并不完美。因为只有在 single
未创建时,我们加锁才是有必要的。如果 single
已经创建.这时候锁不仅没有好处,而且还会影响到程序执行的性能(多个线程执行 @synchronized
中的代码时,只有一个线程执行,其他线程需要等待)。那么有没有方法既可以解决问题,又不影响性能呢?
这个方法就是GCD中的dispatch_once
@implementation Singleton + (instancetype)shareInstance { static Singleton* single; static dispatch_once_t onceToken; //①onceToken = 0; dispatch_once(&onceToken, ^{ NSLog(@"%ld",onceToken); //②onceToken = 140734731430192 single = [[Singleton alloc] init]; }); NSLog(@"%ld",onceToken); //③onceToken = -1; return single; } @end 复制代码
dispatch_once
为什么能做到既解决同步多线程问题又不影响性能呢?
下面我们来看看 dispatch_once
的原理:
dispatch_once
主要是根据 onceToken
的值来决定怎么去执行代码。
-
当
onceToken
= 0时,线程执行dispatch_once
的block
中代码 -
当
onceToken
= -1时,线程跳过dispatch_once
的block
中代码不执行 -
当
onceToken
为其他值时,线程被线程被阻塞,等待onceToken
值改变
当线程首先调用 shareInstance
,某一线程要执行 block
中的代码时,首先需要改变 onceToken
的值,再去执行block中的代码。这里 onceToken
的值变为了140734731430192。
这样当其他线程再获取 onceToken
的值时,值已经变为140734731430192。其他线程被阻塞。
当 block
线程执行完 block
之后。 onceToken
变为-1。其他线程不再阻塞,跳过 block
。
下次再调用 shareInstance
时,block已经为-1。直接跳过 block
。
这样 dispatch_once
在首次调用时同步阻塞线程,生成单例之后,不再阻塞线程。 dispatch_once
是创建单例的最优方案
总结:
dispatch_once
单例虽然好用,不过他并不适合继承和扩展,所以使用单例的时候要注意这点。千万不要任何东西都使用单例,要适可而止
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- OC对象的本质 实例对象,类对象,元类对象
- 可迭代对象,迭代器(对象),生成器(对象)
- 重学前端学习笔记(七)--JavaScript对象:面向对象还是基于对象?
- Webform 内置对象 Session对象、Application全局对象,ViewState详细介绍
- 对象.原型链,函数.原型对象
- Java 对象组成,对象头分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
用户力:需求驱动的产品、运营和商业模式
郝志中 / 机械工业出版社 / 2015-11-1 / 59.00
《用户力:需求驱动的产品、运营和商业模式》从用户需求角度深刻阐释了互联网产品设计、网络运营、商业模式构建的本质与方法论! 本书以“用户需求”为主线,先用逆向思维进行倒推,从本质的角度分析了用户的需求是如何驱动企业的产品设计、网络运营和商业模式构建的,将这三个重要部分进行了系统性和结构化的串联,然后用顺向思维进行铺陈,从实践和方法论的角度总结了企业究竟应该如围绕用户的真实需求来进行产品设计、网......一起来看看 《用户力:需求驱动的产品、运营和商业模式》 这本书的介绍吧!