如何将 KVO 添加到 synchronized class?
How to add KVO to synchronized class?
在我的应用程序中,您可以在下面看到 Restaurant
class。我想附加一个 KVOController
到它。但我没有运气。当我用下面的代码附加它时,它崩溃了。
FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
self.KVOController = KVOController;
[self.KVOController observe:self keyPath:@"[Restaurant current].name.asString" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
DDLogDebug(@"Restaurant changed");
}];
将 KVO 添加到这样的 class 中的最佳方法是什么?
@implementation Restaurant
static Restaurant *current = nil;
+ (Restaurant *)current {
@synchronized(self) {
if (current == nil) {
current = [[Restaurant alloc] initWithId:0];
}
}
return current;
}
- (id)initWithId:(NSInteger)number {
self = [super init];
if (self)
{
...
}
return self;
}
@end
问题不在于@synchronized
。您的代码存在几个问题:
- 是否要观察当前餐厅的变化?或者当当前餐厅的名称更改时(没有
+[Restaurant current]
指向不同的餐厅实例)。或者任何类型的名称更改,无论是由 current
的更改还是 name
的更改触发的?
- 根据答案,您可能想要观察
observe:[Restaurant class]
或 observe:[Restaurant instance]
,但绝对不是 observe:self
(除非您在 Restaurant
class 实现,在这种情况下 [self class]
将替代 [Restaurant class]
)。
- 要使任何更改可见,您必须确保 class 以 KVO-compliant 方式实施。这既适用于
+[Restaurant current]
的更改,也适用于 -[Restaurant name]
的更改,具体取决于您希望能够观察到的内容。
[Restaurant current].name.asString
不是有效的密钥路径。有效的键路径只能包含 属性 名称(ASCII,以小写字母开头,无空格)和分隔它们的点(有关详细信息,请参阅 Key-value coding)。一旦你告诉 KVOController observe:[Restaurant class]
,关键路径剩下的就是 current.name.asString
.
- 如果不是字符串,
name
是什么?您真的需要将其转换为字符串以进行观察吗?如果您的目的是观察名称更改,观察 current.name
可能就足够了。
您最终可能会选择以下两个选项之一:
FBKVOController *kvoController = [FBKVOController controllerWithObserver:self];
[kvoController observe:[Restaurant class] keyPath:@"current.name" ...];`
// or
[kvoController observe:[Restaurant current] keyPath:@"name" ...];`
同样,要观察到任何变化,它们需要 KVO-compliant。
在我的应用程序中,您可以在下面看到 Restaurant
class。我想附加一个 KVOController
到它。但我没有运气。当我用下面的代码附加它时,它崩溃了。
FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
self.KVOController = KVOController;
[self.KVOController observe:self keyPath:@"[Restaurant current].name.asString" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
DDLogDebug(@"Restaurant changed");
}];
将 KVO 添加到这样的 class 中的最佳方法是什么?
@implementation Restaurant
static Restaurant *current = nil;
+ (Restaurant *)current {
@synchronized(self) {
if (current == nil) {
current = [[Restaurant alloc] initWithId:0];
}
}
return current;
}
- (id)initWithId:(NSInteger)number {
self = [super init];
if (self)
{
...
}
return self;
}
@end
问题不在于@synchronized
。您的代码存在几个问题:
- 是否要观察当前餐厅的变化?或者当当前餐厅的名称更改时(没有
+[Restaurant current]
指向不同的餐厅实例)。或者任何类型的名称更改,无论是由current
的更改还是name
的更改触发的?- 根据答案,您可能想要观察
observe:[Restaurant class]
或observe:[Restaurant instance]
,但绝对不是observe:self
(除非您在Restaurant
class 实现,在这种情况下[self class]
将替代[Restaurant class]
)。 - 要使任何更改可见,您必须确保 class 以 KVO-compliant 方式实施。这既适用于
+[Restaurant current]
的更改,也适用于-[Restaurant name]
的更改,具体取决于您希望能够观察到的内容。
- 根据答案,您可能想要观察
[Restaurant current].name.asString
不是有效的密钥路径。有效的键路径只能包含 属性 名称(ASCII,以小写字母开头,无空格)和分隔它们的点(有关详细信息,请参阅 Key-value coding)。一旦你告诉 KVOControllerobserve:[Restaurant class]
,关键路径剩下的就是current.name.asString
.- 如果不是字符串,
name
是什么?您真的需要将其转换为字符串以进行观察吗?如果您的目的是观察名称更改,观察current.name
可能就足够了。
您最终可能会选择以下两个选项之一:
FBKVOController *kvoController = [FBKVOController controllerWithObserver:self];
[kvoController observe:[Restaurant class] keyPath:@"current.name" ...];`
// or
[kvoController observe:[Restaurant current] keyPath:@"name" ...];`
同样,要观察到任何变化,它们需要 KVO-compliant。