覆盖singleton类的alloc init

时间:2014-02-24 07:12:55

标签: iphone objective-c singleton

我正在我的框架中编写一些单例类,我不希望其他开发人员在这些单例类上调用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方法的实现是否合适?

提前致谢!

2 个答案:

答案 0 :(得分:3)

您问“ alloc和init方法的实现是否合适?

取决于您如何定义“正确的”......

你的代码不正确,因为它通常会起作用,但init就是说,过于谨慎并且有点不正确,你错过了一两招。

查看init,你加倍检查初始化是否已经运行:

  1. dispatch_once;和
  2. BOOL标志init
  3. 传递给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相同的算法。

    然后是copycopyWithZone:对。如果您需要单身人士,则不要复制它,因此您应该实施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之外的任何调用来实例化单例是编程错误。您不编写复杂的代码来防止编程错误。无论如何你永远不会把它弄好: - )