super allocWithZone在单例类概念中有一些疑问

时间:2012-08-06 10:18:33

标签: objective-c

我是Objective-C的新手,我正在尝试基于Apple's documentation创建一个单例类。

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

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

在此代码中sharedManager是一个静态方法,它将检查此类的对象是否存在。如果是这样,它将返回先前创建的对象,否则它将创建一个新对象。

我有一些问题:

  1. 如果sharedManager是静态的,如何访问super

  2. 当我打印[super class]时,为什么会提供当前的班级名称?

  3. 为什么[[super allocWithZone:NULL] init]会返回当前的类对象?

  4. 如果super等于self,那么为什么它不会调用当前类allocWithZone:(NSZone *)zone

3 个答案:

答案 0 :(得分:3)

这里有几件事需要考虑。首先,Cocoa Fundamentals指南有点过时了。它没有考虑Apple开发的一些当前技术,如Grand Central Dispatch和Automated Reference Counting。你的allocWithZone方法中的[retain]无法在启用ARC的项目中正确编译(因为你是Obj-C的新手,我在这里假设你是iOS / iPhone的新手,所以你应该阅读这两项技术)。

在这个帖子中对不同的单例设计模式进行了非常好的讨论: What should my Objective-C singleton look like?

然而,这是一个较旧的主题,因此没有考虑自动引用计数(我多年来一直使用Louis Gerbang的答案,它不再适用于启用ARC的项目)。

对于启用ARC的项目/文件(是的,只能为单个文件启用ARC) - 我们已经转移到使用GCD的单例并且运行良好:

static YourClassName * volatile sharedInstance = nil;

+ (YourClassName *)sharedInstance
{
    static dispatch_once_t sharedInstanceToken;
    dispatch_once(&sharedInstanceToken, ^{
        sharedInstance = [[YourClassName alloc] init];
    });
    return sharedInstance;
}

这里发生了什么?好吧,如果你仔细查看GCD docs,你会看到dispatch_once只在特定对象的应用程序的整个生命周期内执行一次。正如文档所说,这使得它以线程安全的方式创建单例非常有用。

最重要的是,我们将sharedInstance方法声明为volatile,这意味着编译器/运行时永远不应该尝试缓存对方法的调用,并且应该始终执行内部代码。这确保我们总是调用GCD并且我们总是回到我们应该的对象。

由于你是Obj-C的新手,我正在掩饰一大堆,但是肯定会看一下GCD,ARC,然后一旦你在Obj-C中有了坚实的基础,就会看看IMP缓存,这是波动阻止发生的事情。

答案 1 :(得分:3)

其他答案,虽然他们指出关于单身人士的良好信息,但实际上没有回答你的问题。你的问题实际上主要是基于面向对象,你特意引用单身的事实是偶然的。

  1. 我参考self回答了this question,这是答案的重要部分

      

    super在类级别上下文中有意义,但它指的是超类本身,而不是实例

  2. 这个也让我失望了。我问this question并得出结论:

      

    [super class]调用当前实例上的super方法(即self)。如果self有一个被覆盖的版本,那么它将被调用,它看起来会有所不同。由于您没有覆盖它,因此调用[self class]与调用[super class]相同。

  3. 你确定它实际上正在返回这个类的实例吗?或者您是将它分配给此类的实例sharedGizmoManager

  4. Super不等于self,但是你调用的一些方法:例如: [super class]正在调用[self class]将调用的方法的相同实现。

答案 2 :(得分:3)

(1。)'静态函数'中的super是什么?在Objective-C中,+方法被正确地称为类方法, - 方法被称为实例方法。这些+方法不是真正的静态方法,因为Objective-C classes are themselves objects of an opaque type called Class。因此,superself都在+方法中定义。 super将消息发送到 MyGizmoClass 的超类,但是当从+方法super调用时,查找等效的+方法,并且从-method {{1}调用时找到一个相应的方法。在 MyGizmoClass 的方法中的super返回 MyGizmoClass ,这是 Class ,而inmethods self是指向 MyGizmoClass 实例的指针。

(2。)方法self返回+class。是self.isa调用超类: [super class]方法,但是,当+class传递给+方法时,其值和类型都不会被修改(而self 1}}的类型在通过-methods向上传递时被强制转换为超类。因此,当链上的self方法的实现请求+class时,它会获得相同的值 MyGizmoClass
首先,您可以通过从 MyGizmoSuperClass 中导出 MyGizmoClass 来验证self.isa是否在超类中调用了super覆盖:

+class

打印

  
    

是的,它调用了MyGizmoSuperClass:class
    返回MyGizmoClass

  

(3。)再次 @interface MyGizmoSuperClass : NSObject @end @implementation MyGizmoSuperClass +(Class) class { NSLog(@"yes it calls MyGizmoSuperClass:class"); return [super class]; } @end @interface MyGizmoClass : MyGizmoSuperClass +(Class) classviasuper; @end @implementation MyGizmoClass +(Class) classviasuper { return [super class]; //which version of class will super call? } @end int main(int argc, char *argv[]) { NSLog(@"returned %@",[MyGizmoClass classviasuper]); } 调用super的超类版本,但传递给该方法的allocWithZone值仍然指向 MyGizmoClass ,并且self返回接收者类的对象,然后返回 MyGizmoClass

(4。)您可以轻松验证allocWithZonesuper的不同之处。如果您实现self,您的代码将调用 MyGizmoClass [self allocWithZone:NULL]实现并无限循环。使用allocWithZone,可以调用超类的版本。