使用allocWithZone创建一个单例对象

6

BNRItemStore 是一个单例类,我曾经对为什么必须调用 super allocWithZone: 而不是普通的 super alloc 感到困惑。然后覆盖 alloc 而不是 allocWithZone

#import "BNRItemStore.h"

@implementation BNRItemStore

+(BNRItemStore *)sharedStore {
    static BNRItemStore *sharedStore = nil;

    if (!sharedStore)
        sharedStore = [[super allocWithZone: nil] init];

    return sharedStore;
}

+(id)allocWithZone:(NSZone *)zone {
    return [self sharedStore];
}

@end
2个回答

10
[super alloc]将调用allocWithZone:,而你已经重写了allocWithZone:以执行其他操作。为了实际获得超类的allocWithZone:实现(这正是你想要的),而不是覆盖版本,你必须显式地发送allocWithZone:super关键字表示与self相同的对象;它只是告诉方法调度机制开始在超类中查找相应的方法,而不是当前类。
因此,[super alloc]会向上到超类,并在那里获取实现,其实现如下:
+ (id) alloc
{
    return [self allocWithZone:NULL];
}

在这里,self 仍代表您的自定义类,因此会运行您重写的 allocWithZone: 方法,从而将您的程序发送到一个无限循环中。


是的。重写allocWithZone:的原因是限制该类的任何用户创建另一个实例。他们将调用alloc(或可能直接调用allocWithZone:);而不是分配新实例,您将返回现有实例。这是使类成为单例的关键部分。 - jscs
哦,我明白了。那么在调用super alloc和重写alloc与调用super allocWithZone:和重写allocWithZone:之间做出决定是完全随意的吗? - stumped
谢谢,这次交流真的很有帮助! - stumped
1
@W'rkncacnter谢谢你的解释,伙计,但是我还有一个问题要问你:为什么[super alloc]会返回我们自定义类的一个实例呢?难道不是因为super这个关键字调用了父类的alloc方法吗?我弄不明白为什么[super alloc]会返回我们自定义类的实例,而不是NSObject的一个实例 - 也就是super类的实例。(在OP的代码中,接口声明是@interface BNRItemStore : NSObject,我也在读同一本书 :) - Fred Collins
@Fred:你应该将这个问题单独发布,因为你会得到更清晰和更好的答案,而不是只能放在评论中。super会去查找超类中方法的实现代码。调用方法的对象身份与self相同。因此,超类的alloc实现会执行类似于“获取大小为self类的零内存块”的操作,而不是“获取在此方法中实现的类的内存块”。如果是后者,每个子类都必须提供自己的alloc - jscs
显示剩余5条评论

3

根据苹果公司的文档

这个方法是出于历史原因而存在的;Objective-C不再使用内存区域。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接