单例模式是一种非常常见的设计模式,之前文章中UIApplication就是一种典型的单例模式,单例理解起来叶很简单,就不是不管如果访问始终只有一个实例化对象,定义全局共享的变量,如果对象是空则初始化一个对象,如果对象已经存在则使用已经实例化的对象。单例设计模式的作用是使得这个类的一个对象成为系统中的唯一实例,因此需要用一种唯一的方法去创建这个对象并返回这个对象的地址。下面有一张苹果官网的图片可以参考一下:
定义一个Food类,大家共享同一个食物,定义一个静态变量,一个实例方法:
static Food *sharedFoodObj=nil; +(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[Food alloc]init]; } return sharedFoodObj; }
执行以下代码,最后发现两个实例对象food和foodNext地址是一样的:
Food *food=[Food sharedFood]; Food *foodNext=[Food sharedFood]; NSLog(@"共享地址:%p-共享地址:%p",food,foodNext);
如果每次都遵守规则调用sharedFood方法,单例模式算是完成了,但是对象是可以实例化的,看一段下面的代码:
Food *food=[Food sharedFood]; Food *foodInit=[[Food alloc]init]; NSLog(@"共享地址:%p-实例地址:%p",food,foodInit);
food和foodInit的地址是不一样,这个时候我们需要动手改造以下改成的方法,让实例化对象的出来的地址也是一样的,这个时候需要重写allocWithZone方法:
+(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[super allocWithZone:NULL]init]; } return sharedFoodObj; } +(instancetype)allocWithZone:(struct _NSZone *)zone{ return [self sharedFood]; }
如果对象拷贝的时候也需要是同一对象的话,可以加一个方法:
+(id)copyWithZone:(struct _NSZone *)zone{ return [self sharedFood]; }
如果为了确保多线程情况下,仍然确保实体的唯一性,这个时候可以加上@synchronized,@synchronized的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。单例模式或者操作类的static变量中使用比较多。当两个并发线程访问同一个对象@synchronized(self)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
+(Food *)sharedFood{ @synchronized(self){ if (!sharedFoodObj) { sharedFoodObj=[[Food alloc]init]; } } return sharedFoodObj; }
苹果Mac OS 10.6和iOS4.0后引入了GCD,利用GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)实现单例,这个时候我们可以通过dispatch_once简单的实现,代码如下:
+ (instancetype)sharedInstance { static Food *sharedFoodObj = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedFoodObj =[[super allocWithZone:NULL]init]; }); return sharedFoodObj; }
Food.m中的代码:
// // Food.m // Demo //Http://www.cnblogs.com/xiaofeixiang // Created by keso on 15/2/8. // Copyright (c) 2015年 keso. All rights reserved. // #import "Food.h" @implementation Food static Food *sharedFoodObj=nil; +(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[super allocWithZone:NULL]init]; } return sharedFoodObj; } // +(id)copyWithZone:(struct _NSZone *)zone{ return [self sharedFood]; } - (id)copyWithZone:(NSZone *)zone { return self; } + (instancetype)sharedInstance { static Food *sharedFoodObj = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedFoodObj =[[super allocWithZone:NULL]init]; }); return sharedFoodObj; } +(instancetype)allocWithZone:(struct _NSZone *)zone{ return [self sharedInstance]; } @end
iOS的单例通过以上方式可以实现,网上有些文章实现单例用了七个方法,不过自从有了ARC之后,有些方法Apple已经不需要重写,说一个题外话,昨天有个博客园的园友只字不改抄袭了我的文章,文章下面说明栏也说明过了(博客经个人辛苦努力所得,如有转载会特别申明,博客不求技惊四座,但求与有缘人分享个人学习知识,生活学习提高之用),本人是自己辛苦所得,抄袭转载麻烦留一个链接,技术文章技术人看,做一个技术人需要有些底线~