键值在Swift中观察不显示数组中的插入和删除

我创build了一个包含数组的类。 我在视图控制器中添加了一个观察者,并对该数组进行了一些修改。

问题是,当我打印由observeValueForKeyPath()方法返回的更改字典时,我只能看到种类NSKeyValueChangeSetting的更改。 换句话说,该方法告诉我数组已经改变,为我提供了新旧数组(包含所有元素),但是我想要接收哪些特定项目被添加或删除的信息。

这里是一些示例代码。

这是数组将被观察的类。

private let _observedClass = ObservedClass() class ObservedClass: NSObject { dynamic var animals = [String]() dynamic var cars = [String]() class var sharedInstance: ObservedClass { return _observedClass } } 

这是我的视图控制器的代码。

 class ViewController: UIViewController { var observedClass = ObservedClass.sharedInstance required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) observedClass.addObserver(self, forKeyPath: "animals", options: .New | .Old, context: nil) } deinit { observedClass.removeObserver(self, forKeyPath: "animals") } override func viewDidLoad() { super.viewDidLoad() observedClass.animals.insert("monkey", atIndex: 0) observedClass.animals.append("tiger") observedClass.animals.append("lion") observedClass.animals.removeAtIndex(0) } override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) { println(change) } } 

当我运行上面的代码,我得到这个结果在控制台上:

 [kind: 1, old: ( ), new: ( monkey )] [kind: 1, old: ( monkey ), new: ( monkey, tiger )] [kind: 1, old: ( monkey, tiger ), new: ( monkey, tiger, lion )] [kind: 1, old: ( monkey, tiger, lion ), new: ( tiger, lion )] 

不应该,在这个例子中,更改字典显示每个新的项目,因为它被添加到数组,使用更改种类NSKeyValueChangeInsertion?

根据Swift指南:

对于数组,只有在执行可能修改数组长度的操作时才会进行复制。 这包括追加,插入或删除项目,或使用范围下标来replace数组中的一系列项目。

append操作为例。 在后面,当你追加到你的数组时,Swift在内存中创build一个新的数组,将现有的animals数组中的项目复制到这个新的数组中 – 加上新的项目 – 然后将这个新的数组赋值给animalsvariables。 这一手段是为什么你只能得到1Setting ),因为实际上每个“ 编辑 ”实际上导致创build一个新的数组。

这与NSMutableArray不同,因为行为更直观一些 – 编辑现有的数组(不存在幕后复制到新数组),所以编辑之后存在的数组与之前存在的数组是相同的它 – 因此存储在change字典中的键值NSKeyValueChangeKindKey可以是.Insertion.Removal等中的一个。

即使这不是全部的事情,但是,因为你做一个KVO兼容的方式更改为一个NSMutableArray取决于你是否使用Swift或Objective-C。 在Objective-C中,苹果强烈build议实现他们称之为可选的可变索引访问器 。 这些只是具有标准签名的方法,可以非常有效地进行符合KVO的更改。

 // Mutable Accessors /////////////////////////////////////////// // This class has a property called <children> of type NSMutableArray // MUST have this (or other insert accessor) -(void)insertObject:(NSNumber *)object inChildrenAtIndex:(NSUInteger)index { [self.children insertObject:object atIndex:index]; } // MUST have this (or other remove accessor) -(void)removeObjectFromChildrenAtIndex:(NSUInteger)index { [self.children removeObjectAtIndex:index]; } // OPTIONAL - but a good idea. -(void)replaceObjectInChildrenAtIndex:(NSUInteger)index withObject:(id)object { [self.children replaceObjectAtIndex:index withObject:object]; } 

Swift似乎没有这些,所以唯一的方法是通过可变代理对象(在NSKeyValueCoding页面中描述)进行符合KVO的更改。 这是一个非常快速的例子:

 @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { dynamic var children: NSMutableArray = NSMutableArray() //////////////////////////////////// func applicationDidFinishLaunching(aNotification: NSNotification) { addObserver(self, forKeyPath: "children", options: .New | .Old, context: &Update) // Get the KVO/KVC compatible array var childrenProxy = mutableArrayValueForKey("children") childrenProxy.addObject(NSNumber(integer: 20)) // .Insertion childrenProxy.addObject(NSNumber(integer: 30)) // .Insertion childrenProxy.removeObjectAtIndex(1) // .Removal } }