带有参数 iOS 的单例
Singleton with parameter iOS
我需要实现一个接受参数的单例 class。每次都会将同一个对象作为参数传递,因此生成的单例对象将始终相同。
我正在做类似下面代码的事情。这看起来不错吗?有没有更好的方法来实现我想要实现的目标?
- (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;
}
objA = [Object sharedInstanceWithAccount:A];
objB = [Object sharedInstanceWithAccount:B];
B 被忽略。
objB 中的 userAccount 是 A.
如果 objB 中的 userAccount B,您将更改 sharedInstanceWithAccount。
- (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;
}
这个设计中存在一些问题:
按照 Apple 的建议,对于单例,应该 dispatch_once
而不是 @synchronized(self)
:
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;
更多细节请参考这个问题:Why does Apple recommend to use dispatch_once for implementing the singleton pattern under ARC?
将单例放入 alloc
的错误 API
设计。
如方法名称alloc
所示,这意味着将分配一些内存。但是,就您而言,事实并非如此。这种覆盖 alloc
的尝试将导致您团队中的其他程序员感到困惑。
在你的 -init
中使用 NSAssert
是个坏主意。
如果你想禁用一个方法,把它放在你的头文件中来禁用它:
- (id)init __attribute__((unavailable));
在这种情况下,您会得到一个编译错误,而不是在 运行 时使应用程序崩溃。
有关详细信息,请参阅此 post:
此外,您甚至可以添加不可用消息:
- (id)init __attribute__((unavailable("You cannot init this class directly. It needs UserAccountDataSource as a parameter")));
有时会忽略输入参数而不会发出警告。
在您的以下代码中,如果 class 的实例已由其他人创建,调用此函数的程序员如何知道输入参数 userAccount
有时会被忽略?
- (id)sharedInstanceWithAccount:(UserAccount *)userAccount {
if (!sharedInstance) {
@synchronized(self) {
sharedInstance = [[[self class] alloc] initWithAccount:userAccount];
}
}
return sharedInstance;
}
总之,不要认为创建带参数的单例是个好主意。使用传统的单例设计要干净得多。
我需要实现一个接受参数的单例 class。每次都会将同一个对象作为参数传递,因此生成的单例对象将始终相同。
我正在做类似下面代码的事情。这看起来不错吗?有没有更好的方法来实现我想要实现的目标?
- (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;
}
objA = [Object sharedInstanceWithAccount:A];
objB = [Object sharedInstanceWithAccount:B];
B 被忽略。 objB 中的 userAccount 是 A.
如果 objB 中的 userAccount B,您将更改 sharedInstanceWithAccount。
- (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;
}
这个设计中存在一些问题:
按照 Apple 的建议,对于单例,应该
dispatch_once
而不是@synchronized(self)
: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;
更多细节请参考这个问题:Why does Apple recommend to use dispatch_once for implementing the singleton pattern under ARC?
将单例放入
alloc
的错误API
设计。如方法名称
alloc
所示,这意味着将分配一些内存。但是,就您而言,事实并非如此。这种覆盖alloc
的尝试将导致您团队中的其他程序员感到困惑。在你的
-init
中使用NSAssert
是个坏主意。如果你想禁用一个方法,把它放在你的头文件中来禁用它:
- (id)init __attribute__((unavailable));
在这种情况下,您会得到一个编译错误,而不是在 运行 时使应用程序崩溃。 有关详细信息,请参阅此 post:
此外,您甚至可以添加不可用消息:
- (id)init __attribute__((unavailable("You cannot init this class directly. It needs UserAccountDataSource as a parameter")));
有时会忽略输入参数而不会发出警告。
在您的以下代码中,如果 class 的实例已由其他人创建,调用此函数的程序员如何知道输入参数
userAccount
有时会被忽略?- (id)sharedInstanceWithAccount:(UserAccount *)userAccount { if (!sharedInstance) { @synchronized(self) { sharedInstance = [[[self class] alloc] initWithAccount:userAccount]; } } return sharedInstance; }
总之,不要认为创建带参数的单例是个好主意。使用传统的单例设计要干净得多。