我正在我的框架中编写一些单例类,我不希望其他开发人员在这些单例类上调用init和alloc所以我已经覆盖了那些方法,但由于我使用的是ARC,所以我的单例类代码是:< / p>
+(MFSingletonClass*) sharedInstance
{
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
以下是alloc和init方法:
+ (id)alloc {
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
sharedInstance = [super alloc];
});
return sharedInstance;
}
- (id)init {
__weak typeof(self) weakSelf = self;
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
static BOOL init = NO;
if (!init) {
init = YES;
typeof(self) strongSelf = weakSelf;
strongSelf = [super init];
}
});
return weakSelf;
}
我想知道我的alloc和init方法的实现是否合适?
提前致谢!
答案 0 :(得分:3)
您问“ alloc和init方法的实现是否合适?”
取决于您如何定义“正确的”......
你的代码不正确,因为它通常会起作用,但init
就是说,过于谨慎并且有点不正确,你错过了一两招。
查看init
,你加倍检查初始化是否已经运行:
BOOL
标志init
。传递给dispatch_once
的广告块最多只能执行一次,届时init
将为NO
。矫枉过正。删除你得到的:
- (id)init
{
__weak typeof(self) weakSelf = self;
static dispatch_once_t pred = 0;
dispatch_once(&pred,
^{
typeof(self) strongSelf = weakSelf;
strongSelf = [super init];
});
return weakSelf;
}
现在考虑[super init]
,这是对当前实例的方法调用,即虽然不明确,但此表达式引用self
。鉴于您在避免保留周期方面的努力被浪费了。此外,在这些工作中,您将[super init]
的结果分配给了块本地变量strongSelf
,而init
返回weakSelf
- 这就是“通常可以正常工作”备注的原因上面,对[super init]
的大多数调用确实会返回相同的对象,但不需要。如果我们删除弱引用的使用,我们立即解决这两个问题:
- (id)init
{
static dispatch_once_t pred = 0;
dispatch_once(&pred,
^{
self = [super init];
});
return self;
}
Bot不会给我们带来保留周期吗?不,self
引用的对象不保留对块的引用,因此具有返回对象的引用的块无关紧要。
“就此而言”上面的评论
默认的alloc
方法只调用allocWithZone:
,后者需要一个内存区域 - 不再使用的东西,但由于历史原因而存在。因此,您应该真正实现allocWithZone:
而不是alloc
来捕获所有分配 - 代码将遵循与alloc
相同的算法。
然后是copy
和copyWithZone:
对。如果您需要单身人士,则不要复制它,因此您应该实施copyWithZone:
(copy
只会按alloc
/ allocWithZone:
来调用)并返回{{1 }}:
self
错过的技巧
所以除了- (id) copyWithZone:(NSZone *)zone
{
return self;
}
返回不同对象但过于复杂的情况之外,你的代码尽可能地工作;清理[super init]
以解决这个问题。
但是,如果您挖掘Apple现已弃用的Cocoa Objects文档,您会发现Apple建议生成一个真正的单例。在ARC下你可以忽略MRC覆盖,并且可以像你一样添加GCD的使用以确保并发正确性,这将给你留下一个诀窍:Apple通过调用init
来实现allocWithZone:
(您的sharedManager
},然后在sharedInstance
上拨打allocWithZone
。使用您的代码:
super
哪个更干净,但你的方法也很好。
并且知道真正的单身人士和只是共享实例之间的区别而感到荣幸!
HTH
答案 1 :(得分:1)
对于单身人士,你有两个选择:编写非常简单的sharedInstance方法并完成它,或尝试做各种巧妙的技巧,以防止人们实例化更多的对象。尝试通过除sharedInstance之外的任何调用来实例化单例是编程错误。您不编写复杂的代码来防止编程错误。无论如何你永远不会把它弄好: - )