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

     2023-02-16     266

关键词:

【中文标题】super allocWithZone 对单例类概念有一些疑问【英文标题】:super allocWithZone having some doubts in singleton class concept 【发布时间】:2012-08-06 10:18:33 【问题描述】:

我是 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

【问题讨论】:

你可以去my previous post about singleton pattern implementation看看。如果在实现代码中放置了很多 cmets。希望这会有所帮助 你为什么要分配super?你不想要一个 self 的实例吗? 那是一份非常古老的文件。 【参考方案1】:

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

    我参考self回答this question,这是答案的转述,重要部分

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

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

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

    您确定它实际上是在返回这个类的一个实例吗?还是您将其分配给此类的实例sharedGizmoManager

    Super 不等于 self,而是您调用的某些方法:例如[super class] 正在调用 [self class] 将调用的方法的相同实现。

【讨论】:

我认为#2 没有达到目的。 super 是一个不能被覆盖的关键字,它向超类发送消息。在静态 + 方法(不是真正的静态方法,而是 Class 类的动态方法)中,超类是 NSObjectNSObjectclass 方法在使用 super 调用时返回子类,因此 [self class]==[super class] 在静态方法中。 NSObject 的实现如下所示:+(Class)class return self; -- 在这种情况下,self 是子类,因为这是您发送消息的地方。 +(Class)superclass 会有想要的效果,在这种情况下你需要[self superclass];(注意+方法)。 @RiazRizvi,请随时修改答案! 好的,我添加了答案。【参考方案2】:

这里有几件事需要考虑。首先,Cocoa Fundamentals 指南有些过时了。它没有考虑 Apple 开发的一些当前技术,例如 Grand Central Dispatch 和自动引用计数。 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 缓存,这就是 volatile 阻止发生的事情。

【讨论】:

很好的答案,我最近改用这种创建单例的方式,但我从未听说过 volatile 这个词! 虽然你提供了关于单例的很好的信息,但他们只是偶尔引用它们。问题实际上是关于 oop 以及调用了哪些方法的实现。 “我们将 sharedInstance 方法声明为 volatile” - 但是您声明的是静态变量 volatile,而不是方法。 Objective-C 中不存在可变方法,并且方法调用永远不会被优化掉。相反,您应该在方法内移动静态变量。这保证了它在不调用该方法的情况下永远不会被访问。【参考方案3】:

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

(2.) 方法+class 返回self.isa。是的[super class] 调用超类的:+class 方法,但是,当self 被传递给+方法时,它的值和类型都不会被修改(而self 的类型是强制转换的通过 -methods 传递给超类)。所以当+class 方法的实现在链上请求self.isa 时,它会得到相同的值,MyGizmoClass。 可以肯定的是,您可以通过从 MyGizmoSuperClass 派生 MyGizmoClass 来验证 super 确实在超类中调用 +class,您可以在其中放置覆盖: p>

    @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:class 返回 MyGizmoClass

(3.) super 再次调用 allocWithZone 的超类版本,但传递给方法的 self 值仍然指向 MyGizmoClass,并且由于 allocWithZone 返回一个对象接收者的类,你会得到一个MyGizmoClass

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

【讨论】:

创建单例的正确姿势

方法1:  声明:+(instancetype)sharedInstance 单例方法  重写:+(instancetype)allocWithZone:(struct_NSZone*)zone(+(instancetype)alloc和+(instancetype)new都会走allocWithZone,多以直接重写allocWithZone就ok了)     -(instancety 查看详情

在快速测试用例中为单例目标 c 类注入依赖项

...写的。我正在为辅助类编写一个测试用例,但我没有直接对单例类方法进行更改,而是想创建一个模拟单例类,但我不知道该 查看详情

什么是单例?

...为nil,如果是则新建并返回一个本类的实例;****c、重写allocWithZone方法,用来保证其他人直接室友alloc和init视图获得一个新实例的时候不产生一个新实例;****d、适当实现allocWithZone,copyWithZone。release和autorelease。**参考:http://www... 查看详情

Java 单例和同步

...ion【发布时间】:2012-06-2507:44:13【问题描述】:请澄清我对单例和多线程的疑问:在Java中实现Singleton的最佳方法是什么?环境?当多个线程尝试访问getInstance()时会发生什么同时使用方法?我们可以做单例的getInstance()synchronized吗... 查看详情

单例类和元类

】单例类和元类【英文标题】:Singletonclassandmetaclass【发布时间】:2014-08-0507:30:21【问题描述】:我知道单例类是什么。单例类用于保存为对象定义的单例方法。元类和单例类是一样的吗?谁能解释一下什么是元类?关于元类的... 查看详情

Ruby 中 BasicObject 的单例类的单例类

】Ruby中BasicObject的单例类的单例类【英文标题】:SingletonclassofsingletonclassofBasicObjectinRuby【发布时间】:2018-12-1011:00:17【问题描述】:这主要是一个“学术”,但在这里:根据这个Ruby特征类图(稍作编辑):BasicObject.singleton_class.... 查看详情

在打开的单例类中调用单例类方法

】在打开的单例类中调用单例类方法【英文标题】:CallingSingletonClassMethodsInsideOpenSingletonClass【发布时间】:2020-01-0118:19:38【问题描述】:我试图理解为什么我不能从开放类中调用单例类上定义的方法,但我可以从实际类中调用... 查看详情

为啥我对单例的引用为零?

】为啥我对单例的引用为零?【英文标题】:Whymyreferencetosingletonisnil?为什么我对单例的引用为零?【发布时间】:2017-10-1616:40:09【问题描述】:我有这个代码:在我的.h文件中@property(nonatomic,strong)NSMutableDictionary*allInformation;以米... 查看详情

单例模式

单例模式主要有3个特点,:1、单例类确保自己只有一个实例。2、单例类必须自己创建自己的实例。3、单例类必须为其他对象提供唯一的实例。单例模式的实现有多种方法,常见的就有懒汉式单例类和饿汉式单例类。· 懒汉... 查看详情

如何快速创建单例类? [复制]

】如何快速创建单例类?[复制]【英文标题】:Howtocreateasingletonclassinswift?[duplicate]【发布时间】:2015-10-2111:18:35【问题描述】:我需要在Swift中创建一个单例类。谁能帮我写代码?我已经知道单例类在创建通用代码方面非常有帮... 查看详情

序列化对单例模式的破坏(代码片段)

序列化对单例的破坏首先来写一个单例的类:code1packagecom.hollis;importjava.io.Serializable;/***Createdbyhollison16/2/5.*使用双重校验锁方式实现单例*/publicclassSingletonimplementsSerializableprivatevolatilestaticSingletonsingleton;pri 查看详情

单例类(代码片段)

 单例类:该类只能创建一个实例,或者说内存中只有一个实例,该类的对象引用的都是这个实例。 示例:1packagemy_package;23//定义一个单例类4classSingleton5//使用一个类变量来缓存曾经创建过的实例,instance实例6privatestaticSingl... 查看详情

单例类设计问题 [重复]

】单例类设计问题[重复]【英文标题】:SingletonClassdesignIssues[duplicate]【发布时间】:2013-05-0617:04:04【问题描述】:下面是一个使用单例设计模式的类:classSingletonprivatestaticSingletoninstance;privateSingleton()...publicstaticsynchronizedSingletonget... 查看详情

ruby 中的单例类到底是啥?

】ruby中的单例类到底是啥?【英文标题】:Whatexactlyisthesingletonclassinruby?ruby中的单例类到底是什么?【发布时间】:2010-09-1718:21:24【问题描述】:Ruby中的单例类本身就是一个类吗?这就是所有对象都属于“类”的原因吗?这个... 查看详情

单例类

1.单例模式的介绍:  从“单例”字面意思上理解为——一个类只有一个实例,所以单例模式也就是保证一个类只有一个实例的一种实现方法罢了,官方的定义,确保一个类只有一个实例,并提供一个全局访问点,2.单例实现代码... 查看详情

单例模式(代码片段)

...用时才创建序列化和反序列化安全:序列化和反序列化会对单例模式进行破坏反射:防 查看详情

单例类

usingSystem;publicclassSingleton<T>whereT:class,new(){privatestaticreadonlyTs_Instance;staticSingleton(){s_Instance=Activator.CreateInstance<T>();}publicstaticTInstance{get{returns_Instanc 查看详情

Kotlin 中的单例类

】Kotlin中的单例类【英文标题】:SingletonclassinKotlin【发布时间】:2019-01-2022:21:27【问题描述】:我想知道如何在Kotlin中创建一个单例类,以便我的Util类在每次应用执行时只实例化一次。但是,当我将我的Java类转换为kotlin时,生... 查看详情