如何将 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