Ios Swift中的键值不显示数组中的插入和删除
我创建了一个包含数组的类。我在视图控制器中向该阵列添加了一个观察者,并对该阵列进行了一些修改 问题是,当我打印observeValueForKeyPath()方法返回的更改字典时,我只能看到NSKeyValueChangeSetting类型的更改。换句话说,该方法告诉我数组已更改,为我提供了旧数组和新数组(包含所有元素),但我希望收到添加或删除了哪些特定项的信息 下面是一些示例代码 这是将观察其数组的类Ios Swift中的键值不显示数组中的插入和删除,ios,arrays,swift,key-value-observing,Ios,Arrays,Swift,Key Value Observing,我创建了一个包含数组的类。我在视图控制器中向该阵列添加了一个观察者,并对该阵列进行了一些修改 问题是,当我打印observeValueForKeyPath()方法返回的更改字典时,我只能看到NSKeyValueChangeSetting类型的更改。换句话说,该方法告诉我数组已更改,为我提供了旧数组和新数组(包含所有元素),但我希望收到添加或删除了哪些特定项的信息 下面是一些示例代码 这是将观察其数组的类 private let _observedClass = ObservedClass()
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)
}
}
在本例中,更改字典不应该在添加到数组中时显示每个新项,使用更改类别NSKeyValueChangeInsertion?根据Swift指南: 对于阵列,仅当执行可能修改阵列长度的操作时,才会进行复制。这包括追加、插入或删除项,或使用范围下标替换数组中的一系列项 以
append
操作为例。在引擎盖下,当您附加到数组时,Swift会在内存中创建一个新数组,将现有动物数组中的项目复制到这个新数组中,再加上新项目,然后将这个新数组分配给动物变量。这就是为什么你只能得到1
(Setting
),因为实际上每次“编辑”都会产生一个新的数组
与NSMutableArray
不同的是,它的行为更加直观—对现有阵列进行编辑(没有幕后复制到新阵列),因此,编辑后存在的数组与编辑前存在的数组相同-因此,使用键NSKeyValueChangeKindKey
存储在change
字典中的值可以是.insert
、和remove
中的一个
然而,这还不是全部,因为您对NSMutableArray
进行KVO兼容更改的方式取决于您使用的是Swift还是Objective-C。在Objective-C中,苹果强烈建议实施他们称之为可选的。这些只是具有标准签名的方法,可以以非常有效的方式进行符合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];
}
当我使用选项时,我得到了与您相同的结果:.Old |.New
。您是对的,我使用了两个选项,但只使用了一个选项发布代码。这是理想的行为,不是吗?使用此选项,新字典和旧字典都包括在内。我知道observeValueForKeyPath还应该显示添加或删除的项目,以及完整的新旧列表。对于示例的输出,我必须比较两个列表,并自己找出添加或删除了哪些元素。我在Objective中看到了一些例子,其中,当修改数组时,只显示添加和删除的元素,使用值2作为“更改种类”,它对应于NSKeyValueChangeInsertion。你能找到源吗?答案很棒。我将尝试向NSMutableArray添加一个观察者,然后看看会发生什么。谢谢我已经更新了我的答案,加入了有关如何在Swift中对NSMutableArray
进行符合KVO的更改的信息。谢谢您的示例。在看到您的第一个答案后,我尝试使用KVO,只是将原始数组替换为NSMutableArray,但从未调用observeValueForKeyPath函数。使用mutableArrayValueForKey方法完成了这个任务。但是,您认为在Swift中检查数组中的特定更改的最佳方法是什么?回到NSMutableArray,虽然它的工作原理完全符合我的要求,但看起来像是一个黑客,因为我没有使用Swift数据结构。你仍然可以使用苹果建议的可变索引访问器
,只需确保在对象上对willChange:valuesAtIndexes:forKey:
/didChange:valuesAtIndexes:forKey:
的适当调用中包装insertObject:atIndex:
。不确定这是否比使用代理对象好,但这是一个选项。
// 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];
}
@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
}
}