单例模式是开发中最常用的写法之一,创建一个单例很多办法,iOS的单例模式有两种官方写法,如下:
不使用GCD
#import "ServiceManager.h"
static ServiceManager *defaultManager;
@implementation ServiceManager
+(ServiceManager *)defaultManager{
if(!defaultManager)
defaultManager=[[self allocWithZone:NULL] init];
return defaultManager;
}
@end
某些特殊情况下,if执行后面执行的慢了,然后另一个线程用了他,就会创建,if并不安全
使用GCD
#import "ServiceManager.h"
@implementation ServiceManager
+(ServiceManager *)sharedManager{
static dispatch_once_t predicate;
static ServiceManager * sharedManager;
dispatch_once(&predicate, ^{
sharedManager=[[ServiceManager alloc] init];
});
return sharedManager;
}
@end
dispatch_once这个函数,它可以保证整个应用程序生命周期中某段代码只被执行一次!
- 线程安全。
- 满足静态分析器的要求。
- 兼容了ARC
我们看到,该方法的作用就是执行且在整个程序的声明周期中,仅执行一次某一个block对象。简直就是为单例而生的嘛。而且,有些我们需要在程序开头初始化的动作,如果为了保证其,仅执行一次,也可以放到这个dispatch_once来执行。
总结:1.这个方法可以在创建单例或者某些初始化动作时使用,以保证其唯一性。2.该方法是线程安全的,所以请放心大胆的在子线程中使用。(前提是你的dispatch_once_t *predicate对象必须是全局或者静态对象。这一点很重要,如果不能保证这一点,也就不能保证该方法只会被执行一次。)
//单例创建的写法
http://blog.csdn.net/lovefqing/article/details/8516536
//单例创建写法的原因
http://blog.sina.com.cn/s/blog_4cd8dd130101mi37.html
ios 中如何实现一个真正的单利模式
一个常见的担忧是它们常常不是线程安全的。这个担忧十分合理,基于它们的用途:单例常常被多个控制器同时访问。
1.首先要保证allocWithZone是线程安全,当中调用super方法的时候使用dispatch_once方法锁住
2.还要保证单利实现方法中也使用了dispatch_once方法锁住创建对象过程
//dispatch_once的作用正如其名:对于某个任务执行一次,且只执行一次。 dispatch_once函数有两个参数,第一个参数predicate用来保证执行一次,第二个参数是要执行一次的任务block。
//dispatch_once被广泛使用在单例、缓存等代码中,用以保证在初始化时执行一次某任务。
//dispatch_once在单线程程序中毫无意义,但在多线程程序中,其低负载、高可依赖性、接口简单等特性,赢得了广大消费者的一致五星好评。
//(mutableCopy深 与Copy浅,字面理解,能变的是深拷贝)
//浅拷贝,就是只创建一个同类型对象返回
//深拷贝就是,不但创建一个同类型对象回去,并且这个对象中所有的属性值一并都赋值过来
//深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝
//copy是创建一个新对象(copy 是内容拷贝),retain是创建一个指针,引用对象计数加1(指针拷贝)
//使用区别
//mutableCopy得到一个新的可变对象,可以看到它的地址和原来对象的地址是不同的,也就是新对象的retainCount从0-1。
//而copy得到的是一个不可变对象,这里分为两种情况:1、如果原来的对象也是一个不可变的,那么他们的地址指向同一个地址,也就是说它们同一个对象,只是把retainCount加1了而已,2、原来的对象是一个可变对象,那么它会新生成一个不可变对象,地址不同,也是retainCount从0-1。