iOS中的单例你用对了么?

来源:互联网 发布:万信达软件官网 编辑:程序博客网 时间:2024/06/16 11:47

单例模式怎么定义的,可能在不同的语言,不同的书中不完全一样,但是概况开来都应该是:一个类有且仅有一个实例,并且自行实例化向整个系统提供。

因此,首先你可能需要确定你是真的需要一个单例类,还是说仅仅是需要一个方便调用的实例化方法。如果你是真的需要一个单例类,那么你就应该确保这个单例类,有且仅有一个实例(不管怎么操作都只能获取到这个实例)。

最近看到一些github上的单例使用,别人的用法,有一些思考,然后写demo测试了下,就这个简单的单例也有一些坑呢,希望能给他人一些提醒。

我们通常在OC中实现一个单例方法都是这样
static HLTestObject *instance = nil;+ (instancetype)sharedInstance{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        instance = [[[self class] alloc] init];    });    return instance;}

可是这样就可以了么?我做了如下测试:
HLTestObject *objct1 = [HLTestObject sharedInstance];NSLog(@"%@",objct1);HLTestObject *objc2 = [[HLTestObject alloc] init];NSLog(@"%@",objc2);HLTestObject *objc3 = [HLTestObject new];NSLog(@"%@",objc3);

看到这个测试,你想到打印结果了么?结果是这样的:

2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf39515510>2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c4b70>2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c4b70></hltestobject: 0x7fcf39515510>

很明显,通过三种方式创建出来的是不同的实例对象,这就违背了单例类有且仅有一个实例的定义。
为了防止别人不小心利用alloc/init方式创建示例,也为了防止别人故意为之,我们要保证不管用什么方式创建都只能是同一个实例对象,这就得重写另一个方法,实现如下:
+ (instancetype)allocWithZone:(struct _NSZone *)zone{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        instance = [super allocWithZone:zone];    });    return instance;}
再次用上面的测试代码,结果是这样的:
2016-05-23 12:57:37.396 PractiseProject[3618:83975] <hltestobject: 0x7f88b9488ac0>2016-05-23 12:57:37.396 PractiseProject[3618:83975] <hltestobject: 0x7f88b9488ac0>2016-05-23 12:57:37.396 PractiseProject[3618:83975] <hltestobject: 0x7f88b9488ac0></hltestobject: 0x7f88b9488ac0></hltestobject: 0x7f88b9488ac0></hltestobject: 0x7f88b9488ac0>

注意如果单例有属性的话,不要重写init方法, 在

+ (instancetype) sharedInstance

方法中初始化,即可,不然,调用init的时候,初始化的属性会覆盖之前的属性




原创粉丝点击