2012-08-06 69 views
7

我是Objective-C中的新成员,我试图创建基于Apple's documentation的单例类。super allocWithZone在单例类概念中存在一些疑问

+ (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

+0

你可以看看[我以前的文章关于单例模式实现](http://stackoverflow.com/questions/6912703/objective-c-static-field-and-implementing-singleton-pattern/6913036#6913036 )。如果在实施代码中提出了很多评论。希望这会有所帮助 – 2012-08-06 11:52:42

+0

你为什么分配超级?你不想要一个自我的例子吗? – 2013-08-06 17:26:35

+0

这是一个令人惊讶的旧文件。 – 2013-08-06 17:26:44

回答

3

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

  1. 我回答this question参考self,这里是意译,答案

    super确实有一流水平的上下文意思的重要组成部分,但它指的是超类本身,而不是实例

  2. 这一个也扔了我。我问this question而且得出结论:

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

  3. 你确定它实际上是返回这个类的实例吗?还是你将它分配给这个类的实例sharedGizmoManager

  4. 超级并不等于自我,但您调用的一些方法如: [super class]正在调用[self class]将调用的方法的相同实现。

+2

我认为#2错过了标记。 super,一个不能被重写的*关键字,将消息发送给超类。在一个静态+方法中(这不是真正的静态方法,而是* Class *类的动态方法),超类是一个* NSObject *。 *当用'super'调用时,NSObject *的* class *方法在静态方法中返回子类,所以'[self class] == [super class]'。 – 2013-08-03 00:56:16

+0

NSObject的实现如下所示: '+(Class)class return self; }' - 'self'在这种情况下,就是子类,因为那是你发送消息的地方。 '+(Class)superclass'将会产生所需的效果,在这种情况下你需要'[self superclass];'(note + method)。 – Ephemera 2013-08-03 01:31:46

+0

@RiazRizvi,随意修改答案! – 2013-08-05 14:54:30

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?

当然,这是一个较旧的线程,因此不会考虑自动引用计数(我使用路易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缓存,这是什么波动是防止发生。

+0

伟大的答案,我最近切换到这种创建单身人士的方式,但我从来没有听说过挥发性这个词! – 2012-08-06 11:32:06

+0

尽管你提供了有关单身人士的良好信息,但他们只是偶然引用他们。问题实际上是关于oop以及调用哪些方法的实现。 – 2012-08-06 12:30:35

+3

“我们将sharedInstance方法声明为volatile” - 但是您声明了静态变量volatile,而不是方法。 Objective-C中不存在易失性方法,并且方法调用永远不会被优化。相反,您应该在方法内移动静态变量。这保证了在不调用方法的情况下永远不会访问它。 – nschum 2013-02-10 22:27:45

3

(1.)什么是'静态函数'中的super?在Objective-C中,+方法被正确地称为类方法, - 方法被称为实例方法。这些+方法不是真正的静态方法,因为Objective-C classes are themselves objects of an opaque type called Class。因此superself都在+方法中定义。 super将消息发送到MyGizmoClass的超类,但是当从+方法调用super查找等效的方法时,并且当从方法super中调用时查找对应的方法。
selfMyGizmoClass返回MyGizmoClass其为一个类,而在 - 方法self +方法是一个指向MyGizmoClass实例。 (2.)+class方法返回self.isa。是[super class]调用超类:+class方法,但是,当self传递给+方法时,其值和其类型都不会被修改(而self的类型在通过方法传递时转换为超类)。所以当执行+class方法上链要求self.isa时,它得到相同的值,MyGizmoClass
要确定,你可以验证super确实通过从MyGizmoSuperClass获得MyGizmoClass调用父类+class在那里你可以放置一个覆盖:

@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]); 
    } 

打印

是它调用MyGizmoSuperClass:类
返回MyGizmoClass

(3)再次super调用的allocWithZone超类版本,但传递给方法仍指向MyGizmoClassself值,因为allocWithZone返回接收器的类的对象,你会得到一个MyGizmoClass回来。

(4.)您可以轻松验证superself不同。如果你实现了[self allocWithZone:NULL],你的代码将会调用MyGizmoClassallocWithZone的实现并无限循环。用[super allocWithZone:NULL],超类的版本被调用。