用GCD写Objective-c的单例模式和C#有比较大的区别
声明h文件
#import <Foundation/Foundation.h> @interface me : NSObject<NSObject> @property (nonatomic) NSInteger age; +(instancetype)makeme; @end
instancetype和id的区别
instancetype返回的是该实例类型,而id返回的是未知类型
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象,便于编写调试
②instancetype只能作为返回值,不能像id那样作为参数
具体原理是利用dispatch_once 来创建一个单实例,因为该函数在程序生命周期内只运行一次
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
第一个参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数是在整个应用程序中只会被调用一次的代码块。
不过众多的dispath_once版本中我认为这个下面这个还不错
#import "me.h" static me *myself; @implementation me +(id)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onetaken; dispatch_once(&onetaken,^{ myself=[super allocWithZone:zone]; }); return myself; } +(instancetype)makeme{ static dispatch_once_t onetaken; dispatch_once(&onetaken, ^{ myself=[[self alloc]init]; }); return myself; } -(id)copy{ return myself; }
这里我们需要弄清楚allocWithZone方法。oc对象的初始化是alloc和init配合。alloc划分内存,init为实例配置参数变量,如对比下面代码,我删除了allocWithZone方法
#import "me.h" static me *myself; @implementation me +(instancetype)makeme{ static dispatch_once_t onetaken; dispatch_once(&onetaken, ^{ myself=[[self alloc]init]; }); return myself; }
下面的例子是如果你如果用了
me *myself=[[me alloc]init];
me *myself1=[me makeme];
你会发现你获得了一个新的实例,。。。myself和myself1是不同的,这货不是单实例。。。当然因为我们用的alloc+init方法已经绕过了dispath_once的方法,单实例也就失效了
这意味着我们需要从实例初始化的地方开始
查看allocWithZone方法的介绍是
使用alloc方法初始化一个类的实例的时候,默认是调用了 allocWithZone 的方法。于是我们可以把这个也堵上就即使用户使用alloc +init 也不会产生新的实例。