Singleton with parameter iOS
我需要实现一个接受参数的单例类。同一个对象将每次作为一个参数传递,因此生成的单例对象将始终相同。
我在做下面的代码。这个看起来可以吗?有没有更好的方法来实现我想要实现的目标?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | - (id)sharedInstanceWithAccount:(UserAccount *)userAccount { if (!sharedInstance) { @synchronized(self) { sharedInstance = [[[self class] alloc] initWithAccount:userAccount]; } } return sharedInstance; } - (id)initWithAccount:(UserAccount *)userAccount { self = [super init]; if (self) { _userAccount = userAccount; } return self; } - (id)init { NSAssert(false, @"You cannot init this class directly. It needs UserAccountDataSource as a paramter"); return nil; } + (id)alloc { @synchronized(self) { NSAssert(sharedInstance == nil, @"Attempted to allocated a second instance of the singleton"); sharedInstance = [super alloc]; return sharedInstance; } return nil; } |
此设计中存在许多问题:
按照苹果公司的建议,如果单台机器的
1 2 3 4 5 6 7 | static MyClass *sharedInstance = nil; static dispatch_once_t onceToken = 0; dispatch_once(&onceToken, ^{ sharedInstance = [[MyClass alloc] init]; // Do any other initialisation stuff here }); return sharedInstance; |
请参考这个问题了解更多细节:为什么苹果建议在arc下使用dispatch_一次来实现singleton模式?
坏的
如方法
在你的
如果要禁用某个方法,请通过将其放入头文件来禁用该方法:
1 | - (id)init __attribute__((unavailable)); |
在这种情况下,您将得到一个编译错误,而不是在运行时崩溃应用程序。请参阅本文了解更多详细信息:覆盖核心数据属性的方法:isDeleted
此外,您甚至可以添加不可用的消息:
1 | - (id)init __attribute__((unavailable("You cannot init this class directly. It needs UserAccountDataSource as a parameter"))); |
有时会忽略输入参数而不发出警告。
在下面的代码中,调用此函数的程序员如何知道,如果某个类的实例已经由其他人创建,则有时会忽略输入参数
1 2 3 4 5 6 7 8 | - (id)sharedInstanceWithAccount:(UserAccount *)userAccount { if (!sharedInstance) { @synchronized(self) { sharedInstance = [[[self class] alloc] initWithAccount:userAccount]; } } return sharedInstance; } |
简而言之,不要认为用参数创建单例是个好主意。使用传统的单件设计更清洁。
1 2 | objA = [Object sharedInstanceWithAccount:A]; objB = [Object sharedInstanceWithAccount:B]; |
B被忽略。objb中的用户帐户是A。
如果objb中有useraccount b,您将更改sharedInstanceWithAccount。
1 2 3 4 5 6 7 8 9 10 11 12 13 | - (id)sharedInstanceWithAccount:(UserAccount *)userAccount { static NSMutableDictionary *instanceByAccount = [[NSMutableDictionary alloc] init]; id instance = instanceByAccount[userAccount]; if (!instance) { @synchronized(self) { instance = [[[self class] alloc] initWithAccount:userAccount]; instanceByAccount[userAccount] = instance; } } return instance; } |