iOS单例的精心设计历程

单例在开发过程中,几乎所有的项目都会用到。当然想让一个对象在整个运行的过程中的地址只使用一个的方法有很多。比如在AppDelegate中提供一个只读属性, 仅仅在.m文件中创建一次, 那么这个对象在整个运行中也能保证只是一个地址。但是这种方式也太屌丝了, 接下来还是来谈谈我们所耳熟能详的单例设计吧。

相信,很多人都说一个单例的设计很简单,一直使用了多年的代码也没有出现过什么问题。不管怎么样,尽然进来了, 就看看我的设计历程吧。。。。。。

1、创建一个单例类

一个干净利落的类叫SingleObject。然后首当其冲的将单例方法实现了,整体代码如下:

.h文件

1
2
3
4
5
6
7
8
9
# import   @ interface   SingleObject : NSObject
/**
  单例类方法
  @return 返回一个共享对象
  */
+ (instancetype)sharedInstance;
// 姓名
@property (nonatomic, copy) NSString* name;
@end

.m文件

1
2
3
4
5
6
7
8
9
10
11
12
13
# import   "SingleObject.h"
@implementation SingleObject
static   SingleObject* kSingleObject = nil;
/** 单例类方法 */
+ (instancetype)sharedInstance {
     static   dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         kSingleObject = [[self allocWithZone:NULL] init];
     });
      
     return   kSingleObject;
}
@end

OK, 一个单例的类这样就OK了,这是我的实验结果:

1198135-f0bccd4de8a5cc7b.png

事实证明,不管调用多少次+ sharedInstance方法, 返回的都是一个对象。

2、allocWithZone:出场

又作了一个实验:

1198135-1c7cb1350d77528d.png

厉害了,我的锅。还是不行,万一有小朋友像我一样不按照套路出场, 直接调用 alloc来创建对象, 那么不就又创建一个对象空间么?于是想到了allocWithZone:方法, 于是这样就被重写了:

1198135-f89ade4667e1fdf8.png

于是,再看看刚刚刚的那时出错实验:

1198135-1985a6afb12755e4.png

厉害了,我的锅,这次错得更离谱了。原因是这个:

1198135-52a26d984ef20cc1.png

于是,就修改一下吧,这样子试试:

1198135-7e7b2da7252f2246.png

这一次,又对了。

然后,由这样的实验了一下:

1198135-5f5a8f21ca393562.png

尽然 so01为空, 静静想想也是合理的, 毕竟第一次直接调用alloc执行allocWithZone:的时候,kSingleObject根本就没有值。

那就这样实现以下吧:

1198135-740430b4950259b1.png

再次实验一下:

1198135-ed1a936c05d0429c.png

嗯, 结果很对!其实到这里就差不多了,先静下来说点其它的吧。

对于一个码农来说,很多的时候只要是结果对了,其它的都是小事。就像上面的这一系列的实现一样,从某种意义上来说allocWithZone:方法,完全没有必要去实现,直接只用 + sharedInstance 不就行了么?!这样的话,代码还很简洁。通常一个单例,谁还会想着去直接去调用alloc来创建对象呢。确实是这样的,如果我在使用单例的时候,直接去调用alloc来创建对象,我自己都感觉到很屌丝。但是,话又说回来,有的时候难免也需要装一下逼,对于程序员来说,一天除了装逼,还有什么可以用来娱乐的呢?!

伙计们、为了更全面的装逼,接下来又要有新问题了。

OC中除了alloc能全新的创建一个地址空间外,还有其它的系统方法:+ newcopy与mutableCopy

3、到new出场了

第一个问题是:在上面实现的前提下,如果直接调用new来创建对象的话,会有出现新的bug么,看看这个实验:

1198135-e4f0a7e6e3e63291.png

看上去很对的样子。[偷笑中]

的确, 这个系统类方法是不需要重写的。好像应该可能肯定这个方法的内部是调用了+alloc-init这两个方法。

所以,在以后看到别人的单例中重写了这个方法的话,你懂的,默默的笑一会儿就可以了。[得意中]

4、轮copy与mutableCopy出场

有一个常识:在OC中的,除了一些特别的类是系统已经支持copy与mutableCopy的,其它的类是需要开发者自己遵守NSCopying与NSMutableCopying这两个协议,然后实现其协议方法来支持copy与mutableCopy方法的。如果没有实现这两个协议方法的话,直接调用copy或者mutableCopy方法是会直接crash的,即使这两个方法是在NSObject中公开的。

对于一个单例来说,是没有必要去实现这两个方法的功能,但是为了代码的严谨性,不对、应该说是为了装逼。也需要去考虑一下,如果别人调用了这两个方法的情况。

所以有了这个下面的代码:

1198135-431c9091e4966fee.png

然后,到了这里有的小伙伴心中又不好受了,说应该是这样来写:

1198135-77e9dccc83b10de3.png

其实,我想说这个也是对的,没有问题,但是我个人感觉没有必要。然后又有一个小伙伴说:“万一kSingleObject的值为空, 怎么办?”,这个问题确实是难倒我了,因为我不知道一个单例的对象调用copy或者mutableCopy方法, 是怎么做到kSingleObject还是为空的????????如果调用了copy或者mutableCopy方法,kSingleObject还是为空,只能说明这个单例设计本身就有问题, 但是设计的这个单例本身是没有问题的嘛。[偷笑中]

整个设计历程,终于结束了,公布收官。又有一个小伙伴不服气起来,怎么就结束了,NSCopying与NSMutableCopying这两个协议还没有见到呢?两个协议方法也没有实现。厉害了,我的锅。我就很纳闷了,这两个协议需要实现么?当说出不需要实现, 像上面重写一下copy与mutableCopy就可以了。话还没有落下,又有一个小伙伴又来事了,说:“别人设计的都重写了NSCopying与NSMutableCopying协议方法的,还调用了+ sharedInstance方法”。刚果不是说了么,单例是不应该支持copy与mutableCopy操作的。重写了copy与mutableCopy方法,就可以了。

到这里, 就真的要收官了

发布中...

发布中...

发布中...

发布中...

发布中...

发布中...

突然又想起,尽然要装逼,为什么不装得更全面一点呢?还有一个ARC与MRC的事情。

5、MRC出场

是的,在OC中有一个MRC的东西。MRC这东西很重要,但是我开发这些年很少用到,但是理解她与分析她还是可以的。想当年,我也能给台下的16个大神在讲台之上分析这个个retainCount值的来龙去脉。这里就不详细介绍了,感兴趣的自学吧,网上大神资料不少。

具体的加上这几句代码:

1198135-6366da1b6fd6ed37.png


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值