单例模式在iOS开发中可能算是最经常使用的模式之一了,可是因为OC自己的语言特性,想要写一个正确的单例模式相对来讲比较麻烦. 今天就来讲一说, 单例建立的方式和严谨的单例写法及可继承单例编写.ios
SingleHandle.hatom
@interface SingleHandle : NSObject //单例建立方法通常以 share, stand, main 开头 + 当前类名 +(SingleHandle *)shareSingleHandle; @end
SingleHandle.mspa
@implementation SingleHandle //声明静态变量 static SingleHandle *singlehanle = nil; +(SingleHandle *)shareSingleHandle { //同步锁 //防止一种极限的可能,第一个对象正在建立的时候,第二个对象就开始建立了,形成两个对象 @synchronized(self){ if (singlehanle == nil) { singlehanle = [[SingleHandle alloc]init]; } return singlehanle; } } @end
Singleton.h.net
@interface Singleton : NSObject +(instancetype) shareInstance; @end
Singleton.mcode
@implementation Singleton static Singleton* instance = nil; +(instancetype) shareInstance { static dispatch_once_t onceToken ; dispatch_once(&onceToken, ^{ instance = [[self alloc] init] ; }) ; return instance ; } @end
通常状况下,可能咱们写的单例模式是上面的方式, 这里再也不赘述, 但这样是不严谨的. 先来看一下到底不严谨的写法缺点是什么.
以上面的方式二举例:对象
Singleton* single1 = [Singleton shareInstance] ; NSLog(@"single1 = %@", single1) ; Singleton* single2 = [Singleton shareInstance] ; NSLog(@"single2 = %@", single2) ; Singleton* single3 = [[Singleton alloc] init] ; NSLog(@"single3 = %@", single3) ; NSLog(@"single4 = %@", [single3 copy]) ;
打印结果:继承
single1 = < Singleton: 0x7ffb93743e80 > single2 = < Singleton: 0x7ffb93743e80 > single3 = < Singleton: 0x7ffb9373ecc0 > -[Singleton copyWithZone:]: unrecognized selector sent to instance 0x7ffb9373ecc0
能够看到,当咱们调用shareInstance方法时获取到的对象是相同的,可是当咱们经过alloc和init来构造对象的时候,获得的对象倒是不同的。并且在 single4 这行注释打开后, 会在此崩溃, 缘由如上. 内存
因此,咱们经过不一样的途径获得不一样的对象,显然是不行的。咱们必需要确保对象的惟一性,因此咱们就须要封锁用户经过alloc和init以及copy来构造对象这条道路。ci
咱们知道,建立对象的步骤分为申请内存(alloc)、初始化(init)这两个步骤,咱们要确保对象的惟一性,所以在第一步这个阶段咱们就要拦截它。当咱们调用alloc方法时,OC内部会调用allocWithZone这个方法来申请内存,咱们覆写这个方法,而后在这个方法中调用shareInstance方法返回单例对象,这样就能够达到咱们的目的。拷贝对象也是一样的原理,覆写copyWithZone方法,而后在这个方法中调用shareInstance方法返回单例对象。开发
@implementation Singleton static Singleton* instance = nil; +(instancetype) shareInstance { static dispatch_once_t onceToken ; dispatch_once(&onceToken, ^{ instance = [[super allocWithZone:NULL] init]; }) ; return instance ; } +(id) allocWithZone:(struct _NSZone *)zone { return [Singleton shareInstance] ; } -(id) copyWithZone:(struct _NSZone *)zone { return [Singleton shareInstance] ; } @end
打印结果:
single1 = < Singleton: 0x7fe2e24a2880 > single2 = < Singleton: 0x7fe2e24a2880 > single3 = < Singleton: 0x7fe2e24a2880 > single4 = < Singleton: 0x7fe2e24a2880 >
这样就是比较正确很严谨的写法了.
可继承单例是指父类中写下单例建立的方法, 当其自己类或其子类调用父类中的类建立的方法时, 能够各自类建立各自类的单例. 因此, 在父类中写的一个方法, 同时适用于其自己和其子类, 故称做可继承单例.
单例类 A :
@interface A : NSObject @property (nonatomic,copy)NSString *a1; + (instancetype)sharedInstance; @end #import "A.h" #import <objc/runtime.h> @implementation A +(instancetype)sharedInstance { id instance = objc_getAssociatedObject(self, @"instance"); if (!instance) { instance = [[super allocWithZone:NULL] init]; NSLog(@"单例建立=====%@=====",instance); objc_setAssociatedObject(self, @"instance", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return instance; } +(id) allocWithZone:(struct _NSZone *)zone { return [self sharedInstance] ; } -(id) copyWithZone:(struct _NSZone *)zone { Class selfClass = [self class]; return [selfClass sharedInstance] ; } @end
单例类 B 和单例类 C 中无任何方法和属性, 只是继承于A类.
执行下面的方法:
A *singleA = [A sharedInstance]; B *singleB = [B sharedInstance]; C *singleC = [C sharedInstance]; singleA.a1 = @"aaa"; singleB.a1 = @"bbb"; singleC.a1 = @"ccc"; NSLog(@"singleA = %p",singleA); NSLog(@"singleB = %p",singleB); NSLog(@"singleC = %p",singleC); NSLog(@"singleA.a1 = %@",singleA.a1); NSLog(@"singleB.b1 = %@",singleB.a1); NSLog(@"singleC.c1 = %@",singleC.a1);
打印结果:
单例建立=====< A: 0x7fc21282fb60 >===== 单例建立=====< B: 0x7fc21282fcb0 >===== 单例建立=====< C: 0x7fc210427190 >===== singleA = 0x7fc21282fb60 singleB = 0x7fc21282fcb0 singleC = 0x7fc210427190 singleA.a1 = aaa singleB.a1 = bbb singleC.a1 = ccc