Objective-C - 动态单例初始化器?

5

我有一个基础的Store类,许多商店都会继承它,每个商店都是单例。目前,每个商店都定义了自己几乎相同的方法:

+ (Store *)instance {
    static SubStore *store = nil;
    if (!store) {
        store = (SubStore *) [[super allocWithZone:nil] init];
        [store setupDefaults];
    }
    return store;
}

有没有一种方法可以制作一个单例方法,使得该方法可以简单地添加到基类中,并被子类继承?

1
我尝试过但从未找到方法。此外,为了保证线程安全,您应该使用dispatch_once块而不是if(!store) - Kevin
我正在跟随书本代码。我会研究dispatch_once。 - Stefan Kendall
2个回答

5

坚持简单愚蠢,但使用dispatch_once。

一旦您尝试使其通用,它就变得复杂。而且容易出现错误。

sharedInstance方法与显式类命名是非常明显的,您不太可能在项目中重复多次。

如果您有一个类的许多子类,则移动到标识符模型。 即,在抽象存储类上具有缓存,可以通过标识符查找存储实例。


我避免使用+initialize或更糟的+load进行此类初始化。两者都是非确定性的,因为它们在与应用程序中的其他子系统的执行顺序可能会非常不同,即使是看似无害的更改也可能导致其行为发生奇怪的变化。

最好完全确定性初始化。在applicationDidFinishLaunching:(或其他之一)中添加一个调用,明确地初始化应用程序中的该特定子系统。它易于遵循,声明和使用都是明确的,并且随着代码库的发展,不会以奇怪的方式改变行为。


我经常将那种初始化代码放在+initialize中。ObjC运行时确保该方法只被调用一次。 - zneak
3
这并不完全正确。如果你有一个带有initialize方法的A类,并且有一个扩展A类的B类,但B类没有实现initialize方法,那么当第一次引用A和B时,A类的initialize方法将被调用两次。 - rmaddy
+load 每个类/分类只会被调用一次。 - nielsbot

2

不要使用一个存储 static SubStore * store = nil;,你可以使用一个 NSMutableDictionary,它使用类名作为键。

简单来说:

#import <Foundation/Foundation.h>

@interface MONStore : NSObject
- (NSString *)nameOfMostPopularItem;
@end

@implementation MONStore

+ (instancetype)sharedStore
{
    // lazy population - not thread safe
    static NSMutableDictionary * stores = nil;
    if (nil == stores) {
        stores = [NSMutableDictionary new];
    }
    NSString * key = NSStringFromClass([self class]);
    if (nil == [stores objectForKey:key]) {
        [stores setObject:[self new] forKey:key];
    }
    return [stores objectForKey:key];
}

- (NSString *)nameOfMostPopularItem
{
    return nil;
}

@end

@interface MONMusicStore : MONStore
@end

@implementation MONMusicStore
- (NSString *)nameOfMostPopularItem { return @"Guitar Strings"; }
@end

@interface MONPetStore : MONStore
@end

@implementation MONPetStore
- (NSString *)nameOfMostPopularItem { return @"Puppies"; }
@end

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSLog(@"--- Shopping List ---\nMusic Store:\n\t%@\n\nPet Store:\n\t%@\n",
                    [MONMusicStore sharedStore].nameOfMostPopularItem,
                    [MONPetStore sharedStore].nameOfMostPopularItem
                    );
    }
    return 0;
}

...这并不是我在我的程序中会做的事情。


你会使用什么替代? - Stefan Kendall
@StefanKendall 我是那些对单例模式抱怨/不赞成的人之一 ;) - justin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接