OC基础-单例的实现 & 提醒自己注意多线程问题

40次阅读

共计 1000 个字符,预计需要花费 3 分钟才能阅读完成。

做客户端开发应当时刻考虑多线程问题。我最初是做前端开发的,在这方面考虑得往往不够。谨记。
单例的常见写法
单例的常见写法其实就两种
1. 依赖锁
+ (id)sharedInstance {
static testClass *sharedInstance = nil;
@synchronized(self) {
if (!sharedInstance) {
sharedInstance = [[self alloc] init];
}
}
return sharedInstance;
}
2. 依赖 dispatch_once
+ (id)sharedInstance {
static testClass *sharedInstance = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
dispatch_once 的写法更推荐一些。一方面是性能上好一点,另一方面是语义上更直观。once,执行一次嘛。
不管是用锁还是 dispatch_once,本质上都是为了避免单例创建过程出现线程安全问题。
更进一步,我们经常会有懒加载某些属性的写法:
– (id<InterfaceEngineA>)engineA
{
if (_engineA == nil) {
_engineA = [EngineA new];
}

return _engineA;
}
其实跟单例的实现是类似的,这种时候要格外注意线程安全问题。如果存在多线程场景,一定要做好保护
– (id<InterfaceEngineA>)engineA
{
@synchronized(self) {
if (_engineA == nil) {
_engineA = [EngineA new];
}
}
return _engineA;
}
一些废话
多线程问题的表现可能是各种各样难以预料的。这里我遇到的是,_engineA 在多线程场景下小概率被重复创建,其实例 1 在 init 时注册了网络层命令字 cmd1 的回包,而这个网络层框架的实现是,只接受第一个注册这一命令字的对象。导致实例 2 注册失败。后面调用实例 2 发送请求,回包都被实例 1 接收了。从日志上看,一切都挺正常的。但是下次取数据就是取不到。
这个 bug 第一次提过来的时候,没分析出根本原因,只在表面上做了保护。结果第二次提过来才真正改掉。
丢人呐。还是要好好学习才是。

正文完
 0