我创建了一个单例类,我想创建一个类,这个类是这个单例类的子类,正确的方法是什么
答案 0 :(得分:20)
我特别不了解Objective-C,但一般来说,单例类应该阻止子类化。如果你有一个基类的实例和一个子类的实例,那么你实际上有两个对象可以看作是基础“单例”类的实例,不是吗?
只要你有两个实例,它就不再是一个单独的实例了......而这就是抛弃多个子类的可能性,或者子类本身允许创建多个实例。
当然你可以改变你的基类,这样它就可以获得一个单独的“默认”实例,但这与使它成为一个单例并不完全相同。
答案 1 :(得分:13)
如果Jon没有说服你不这样做,你应该这样做:
在你的超类中,使用[[[self class] alloc] init]
初始化你的单例实例,这样你就可以得到一个用于调用sharedInstance方法的类的实例。而且您不必覆盖子类中的sharedInstance方法。
[SuperClass sharedInstance] //-> instance of SuperClass
[SubClass sharedInstance] //-> instance of Class
答案 2 :(得分:8)
我为单身人士做了一个“基类”的例子,你可以在这里查看:https://github.com/stel/DOSingleton
答案 3 :(得分:6)
// this code goes in the implementation of the superclass
static Sprocket *defaultSprocket;
+ (instancetype) defaultSprocket
{
if (defaultSprocket == nil)
defaultSprocket = [[[self class] alloc] init];
return defaultSprocket;
}
这种方法具有以下优点:
[self class]
允许例如[SprocketSubclass defaultSprocket]
返回SprocketSubclass
而不是Sprocket
instancetype
允许编译器对此方法的结果进行类型检查:当您调用Sprocket
时调用它+[Sprocket defaultSprocket]
,但调用SprocketSubclass
时调用+[SprocketSubclass defaultSprocket]
它为{{1}}。值得注意的是,您可以在基类中定义此访问器方法,然后您不必在子类中执行任何操作!
(给explaining why instancetype
is so cool的NSHipster和reminding me of it recently的bbum提示。)
答案 4 :(得分:3)
如果您正在寻找的是设置新单身人士的快捷方式。这个伪抽象单例基类是我使用的:
<强>ħ强>
#define CREATE_SHARED_INSTANCE \
+ (instancetype)sharedInstance { \
static dispatch_once_t once; \
static id instance = nil; \
dispatch_once(&once, ^{ \
instance = [[self alloc] init]; \
}); \
return instance; \
}
@interface SharedObject : NSObject
+ (instancetype)sharedInstance;
@end
<强>中号强>
@implementation SharedObject
+ (instancetype)sharedInstance {
[NSException raise:@"Call to unimplemented sharedInstance" format:@"%@ does not implement sharedInstance.", NSStringFromClass([self class])];
return nil;
}
@end
<强>ħ强>
#import "SharedObject.h"
@interface SomeSubclass : SharedObject
@end
<强>中号强>
@implementation SomeSubclass
CREATE_SHARED_INSTANCE
@end
......和任何单身人士一样使用。
[[SomesSubclass SharedInstance] someMethod];
如果调用抽象基类,或者忘记在子类中包含CREATE_SHARED_INSTANCE
,则会引发一个友好的异常。
通过这种方式,您可以在不受性能影响的情况下轻松设置新的单身人士。
答案 5 :(得分:1)
实现这一目标的最简单方法是在类和子类中实现标准的单例访问器。这样每个类的行为都是一个合适的单例,也就是说只有两个实例。如果您尝试在子类中重用父类的访问器,然后如果您使用这两个类,则存在访问者返回错误实例的风险,因为它们的行为将取决于它们的访问顺序。 / p>
您不应该使用instancetype作为单例访问器来帮助防止此错误。您会注意到Apple不会将它用于单身人士,例如UIApplication和CKContainer。
如果您希望访问超类的单例方法的现有代码被赋予子类的实例,那么您可能需要重新设计,请参阅MrJre的答案。
答案 6 :(得分:0)
我遇到了类似的问题,我有多个目标需要稍微不同的单例实现:每个目标都包含基类+特定的子类。这是通过编写基类来实现的:
+ (SingletonBaseClass*) sharedInstance {
static SingletonBaseClass * sharedInstance = nil;
if (!sharedInstance) {
sharedInstance = [[[self class] alloc] init];
[sharedInstance customInit];
}
return sharedInstance;
}
关键区别是[self class]
而不是实际的班级名称。这样,当我们调用:[SingletonSubclass sharedInstance]
时,实例化正确的对象。
请注意,这是一个具体案例,在一般情况下我同意以前的答案。
答案 7 :(得分:0)
我有一个类似的问题,我解决它的方法是创建一个单独的包装类,它具有所有额外的功能。这个单例类包含原始单例(将单例实例作为成员变量)。这样你可以避免肮脏的伎俩。
答案 8 :(得分:0)
我遇到了同样的问题。这是如何解决的:您需要使用静态字典来对单例进行子类化。例如:
A类:NSObject - &gt;单
B组:A
C类:A
@implementation A
// Dictionary that holds all instances of API subclasses
static NSMutableDictionary *_sharedInstances = nil;
+ (instancetype)sharedInstance
{
id sharedInstance = nil;
@synchronized(self)
{
NSString *instanceClass = NSStringFromClass(self);
if (_sharedInstances == nil)
_sharedInstances = [NSMutableDictionary dictionary];
// Looking for existing instance
sharedInstance = [_sharedInstances objectForKey:instanceClass];
// If there's no instance – create one and add it to the dictionary
if (sharedInstance == nil)
{
sharedInstance = [[super allocWithZone:nil] init];
[_sharedInstances setObject:sharedInstance forKey:instanceClass];
}
}
return sharedInstance;
}
现在您可以毫无问题地使用[B sharedInstance]和[C sharedInstance]!
答案 9 :(得分:-4)
@interface SingletonObjC : NSObject
+ (id) sharedInstance;
@end
@implementation SingletonObjC
+ (id) sharedInstance
{
static dispatch_once_t pred;
static id sharedInstance = nil;
dispatch_once(&pred, ^{ sharedInstance = [[self alloc] init]; });
return sharedInstance;
}
@end