我是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
是一个静态方法,它将检查此类的对象是否存在。如果是这样,它将返回先前创建的对象,否则它将创建一个新对象。
我有一些问题:
如果sharedManager
是静态的,如何访问super
?
当我打印[super class]
时,为什么会提供当前的班级名称?
为什么[[super allocWithZone:NULL] init]
会返回当前的类对象?
如果super
等于self
,那么为什么它不会调用当前类allocWithZone:(NSZone *)zone
?
答案 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)
其他答案,虽然他们指出关于单身人士的良好信息,但实际上没有回答你的问题。你的问题实际上主要是基于面向对象,你特意引用单身的事实是偶然的。
我参考self
回答了this question,这是答案的重要部分
super
在类级别上下文中有意义,但它指的是超类本身,而不是实例
这个也让我失望了。我问this question并得出结论:
[super class]
调用当前实例上的super
方法(即self
)。如果self有一个被覆盖的版本,那么它将被调用,它看起来会有所不同。由于您没有覆盖它,因此调用[self class]
与调用[super class]
相同。
你确定它实际上正在返回这个类的实例吗?或者您是将它分配给此类的实例sharedGizmoManager
?
Super不等于self,但是你调用的一些方法:例如: [super class]
正在调用[self class]
将调用的方法的相同实现。
答案 2 :(得分:3)
(1。)'静态函数'中的super
是什么?在Objective-C中,+方法被正确地称为类方法, - 方法被称为实例方法。这些+方法不是真正的静态方法,因为Objective-C classes are themselves objects of an opaque type called Class。因此,super
和self
都在+方法中定义。 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。)您可以轻松验证allocWithZone
与super
的不同之处。如果您实现self
,您的代码将调用 MyGizmoClass 的[self allocWithZone:NULL]
实现并无限循环。使用allocWithZone
,可以调用超类的版本。