用 Swift 编写的 UIViewController 可以充当用 ObjC 编写的对象的观察者吗

Can a UIViewController written in Swift act as an Observer for an Object written in ObjC

我正在尝试观察用 ObjectiveC 编写的对象中 NSMutableArray 的值变化。然而,观察者是一个写在 Swift 中的 UIViewController。 我无法收到 KVO 通知。这些是我的更改:

@interface Record : BaseObject
@property (nonatomic) NSMutableArray *commentsArray;


-(NSUInteger) countOfCommentsArray {
    return _commentsArray.count;
}
-(id) objectInCommentsArrayAtIndex:(NSUInteger)index {
    return [_commentsArray objectAtIndex:index];
}
-(void) insertObject:(Comment *)comment inCommentsAtIndex:(NSUInteger)index {
    [_commentsArray insertObject:comment atIndex:index];
}

-(void) insertComments:(NSArray *)array atIndexes:(NSIndexSet*)indexes {
    [_commentsArray insertObjects:array atIndexes:indexes];
}

-(void) removeCommentsAtIndexes:(NSIndexSet *)indexes {
    [_commentsArray removeObjectsAtIndexes:indexes];
}

-(void) removeObjectFromCommentsAtIndex:(NSUInteger)index {
    [_commentsArray removeObjectAtIndex:index];
}
-(void) replaceObjectInCommentsAtIndex:(NSUInteger)index withObject:(id)object {
    [_commentsArray replaceObjectAtIndex:index withObject:object];
}

BaseObject 派生自 NSObject

在我的观察者 class 中,它是一个 Viewcontroller,写在 Swift 中,我有以下内容。

在其中一种设置方法中。

  myInspectionRecord?.addObserver(self, forKeyPath: "commentsArray", options: NSKeyValueObservingOptions.New, context: nil);

我重写了方法。

  override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        print("Value Changed");
    }

但是不知何故,当我使用 API 本身将新对象添加到数组时,似乎没有触发 observeValue 方法。 关于我可能在这里遗漏的任何指示? 或者 KVO 不能在 Swift 和 Objective C 文件之间工作?

如有任何帮助,我们将不胜感激。 谢谢!

您已经根据 Apple's KVC guide 实现了 to-many key-value coding (!) 方法,但是方法名称是错误的。

由于您的 属性 被命名为 commentsArray,所有方法都需要包含该全名。例如,您的 insertObject:inCommentsAtIndex: 应命名为 insertObject:inCommentsArrayAtIndex:.

根据 this answer 这应该会免费为您提供 KVO 调用,但您必须实际调用它们:编译器似乎认识到它需要为这些方法注入所需的 KVO 调用。

你的代码现在的问题是,你的方法都没有改变属性,即使编译器确实注入了 KVO 代码,它也会这样做错误的密钥路径(comments 而不是 commentsArray)。有两种解决方案:似乎使用那些 KVC-methods 可以免费为您提供 KVO,但我从未使用过这种魔法,所以根据经验我不知道它是否有效。不过应该可以。

如果您想以完全不同的方法修改数组,可以使用 "brute-force" 方法:自己调用 KVO methods willChangeValueForKey: and didChangeValueForKey: or even better, willChange:valuesAtIndexes:forKey: and didChange:valuesAtIndexes:forKey:,如下所示:

[self willChangeValueForKey:NSStringFromSelector(@selector(commentsArray))];
// Modify commentsArray
[self didChangeValueForKey:NSStringFromSelector(@selector(commentsArray))];

// or better, for an insertion:

NSIndexSet *set = [NSIndexSet indexSetWithIndex:someIndex];
NSString *key = NSStringFromSelector(@selector(commentsArray));
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:set forKey:key];
[_commentsArray insertObject:someObject atIndex:someIndex];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:set forKey:key];

(我喜欢使用 NSStringFromSelector(@selector(commentsArray)) 而不是 @"commentsArray",因为编译器随后知道它是一个选择器,并且重构会在您重命名 属性 时警告您。)