8

我有 2 个继承自“MyClass”的子类,每个子类都应该是一个单例。

当我没有任何其他类继承时,我使用此模式获取静态实例:

+ (MyClass *)getInstance
{
    static dispatch_once_t once;
    static MyClass *instance;

    dispatch_once(&once, ^{
        instance = [[MyClass alloc] init];
    });

    return instance;
}

这很好用。现在,如果我添加两个新的子类,FirstClass 和 SecondClass,它们都继承自 MyClass,我如何确保获得各自的 ChildClass?

dispatch_once(&once, ^{
    // No longer referencing 'MyClass' and instead the correct instance type
    instance = [[[self class] alloc] init];
});

FirstClass *firstClass = [FirstClass getInstance]; // should be of FirstClass type
SecondClass *secondClass = [SecondClass getInstance]; // should be of SecondClass type

执行上述操作意味着我总是能取回我将 1st 实例化为我的第二类类型的任何类:

first: <FirstClass: 0x884b720>
second: <FirstClass: 0x884b720>
// Note that the address and type as identical for both.

在不向每个子类添加方法的情况下创建相应的子类单例的最佳方法是getInstance什么?

4

3 回答 3

6

除非你有充分的理由,否则通常应该避免子类化单例。它造成了一个非常混乱的局面。如果你创建一个单例MyClass,你可以创建一个单例FirstClass吗?由于FirstClass必须始终在任何可用的地方MyClass可用(由 Liskov),现在有三个“单例”MyClass对象。现在 ObjC 对单例非常松散,这是一件好事,但这仍然很奇怪。

好的,说了这么多,你的问题呢?首先是解决方案,然后是答案。如上所述,解决方案MyClass可能不应该是单例。摆脱getInstance超类,只需在子类中定义它。

正在发生的事情的答案在您的dispatch_once. 在所有情况下,您都传递了相同的静态once令牌。对于给定的令牌,dispatch_once将运行不超过一次解决这个问题的唯一方法是为每个类传递不同的令牌,我不知道有一种方便的方法可以做到这一点,而无需在每个文件中复制 dispatch_once 代码。您可以尝试once为每个子类创建不同的标记,但这可能比仅仅复制sharedInstance方法更麻烦和代码。

顺便说一句,不要叫它getInstance。“get”在ObjC中有特殊含义,你这里不是那个意思,所以比较混乱。这通常称为sharedInstance,或者sharedSomething在“某事”是您的类的情况下更好。如果您确实是说应该有 aMyClass并且应该有 aFirstClass并且应该有 a SecondClass,那么您可以sharedInstance在所有三个中实现。

于 2012-09-28T02:08:20.937 回答
1

你知道单身狗很粗糙,对吧?许多单身人士是一个更大的问题。谨慎结束。


您可以只使用dispatch_once创建基本单例。那么您的基础可以保存其派生类型的映射(例如字典{key:ClassName|value:Instance})。

您正在使用的dispatch_once建议这将在多线程上下文中使用。在这种情况下,您需要使用互斥锁来保护与字典的交互。

那么来自子类的消息将根据消息传递类 ( self) 确定要查找的类(如有必要,创建该实例)。

于 2012-09-27T23:46:11.820 回答
-1

像这样id在你的第一类中使用myClass

+(instancetype)sharedInstance 
{
    static id sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[[self class] alloc] init];
    });
    return sharedInstance;
}

我认为这应该有效

于 2015-06-08T08:01:34.083 回答