我需要实现一个接受参数的单例类。每次都会将相同的对象作为参数传递,因此生成的单例对象将始终相同。
我正在做类似下面的代码。这看起来不错吗?有没有更好的方法来实现我想要实现的目标?
- (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;
}
答案 0 :(得分:2)
此设计存在许多问题:
根据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?
错误的API
设计将单身人士放入alloc
。
如方法alloc
的名称所示,这意味着将分配一些内存。但是,在你的情况下,它不是。这种覆盖alloc
的尝试将导致团队中其他程序员的混淆。
在NSAssert
中使用-init
的好主意。
如果要禁用方法,请将其放入头文件中以禁用它:
- (id)init __attribute__((unavailable));
在这种情况下,您将收到编译错误,而不是在运行时崩溃应用程序。 有关更多详细信息,请参阅此帖子:Approach to overriding a Core Data property: isDeleted
此外,您甚至可以添加不可用的消息:
- (id)init __attribute__((unavailable("You cannot init this class directly. It needs UserAccountDataSource as a parameter")));
有时会忽略输入参数而不会发出警告。
在下面的代码中,如果该类的实例已由其他人创建,那么调用此函数的程序员如何知道输入参数userAccount
有时会被忽略?
- (id)sharedInstanceWithAccount:(UserAccount *)userAccount {
if (!sharedInstance) {
@synchronized(self) {
sharedInstance = [[[self class] alloc] initWithAccount:userAccount];
}
}
return sharedInstance;
}
简而言之,不要认为使用参数创建单例是个好主意。使用传统的单件设计更加清洁。
答案 1 :(得分:0)
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;
}