Fel*_*rri 9 arrays key-value-observing ios swift
我创建了一个包含数组的类.我在视图控制器中向该数组添加了一个观察者,并对该数组执行了一些修改.
问题是,当我打印observeValueForKeyPath()方法返回的更改字典时,我只能看到类型NSKeyValueChangeSetting的更改.换句话说,该方法告诉我数组已更改,向我提供旧的和新的数组(包含所有元素)但我想收到添加或删除的特定项的信息.
这是一些示例代码.
这是将观察其数组的类.
private let _observedClass = ObservedClass()
class ObservedClass: NSObject {
dynamic var animals = [String]()
dynamic var cars = [String]()
class var sharedInstance: ObservedClass {
return _observedClass
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的视图控制器的代码.
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)
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行上面的代码时,我在控制台上得到了这个结果:
[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
)]
Run Code Online (Sandbox Code Playgroud)
在这个例子中,不应该使用更改类型NSKeyValueChangeInsertion将更改字典显示为添加到数组中的每个新项目.
Pau*_*son 12
根据Swift指南:
对于数组,只有在执行可能会修改数组长度的操作时才会进行复制.这包括追加,插入或删除项目,或使用范围下标来替换数组中的一系列项目.
以一个append
操作为例.在引擎盖下,当你附加到你的数组时,Swift 在内存中创建一个新数组,将现有animals
数组中的项复制到这个新数组 - 加上新项 - 然后将这个新数组分配给animals
变量.这种愚蠢的手段就是为什么你只得到那种1
(Setting
),因为实际上每个' edit '实际上都会导致创建一个新的数组.
这是不同的NSMutableArray
,因为行为更直观的一点-编辑的现有阵列制成(有没有幕后的复制到一个新的数组),所以编辑后存在的阵列是之前存在的相同阵列-因此存储在该值change
与密钥词典NSKeyValueChangeKindKey
可以是一个.Insertion
,.Removal
等等.
然而,即使这不是整个故事,因为NSMutableArray
根据您使用的是Swift还是Objective-C,您对符合KVO标准的更改的方式会有所不同.在Objective-C中,Apple强烈建议实现他们称之为可选的可变索引访问器.这些只是具有标准签名的方法,可以非常有效地进行符合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];
}
Run Code Online (Sandbox Code Playgroud)
Swift似乎没有这些,因此进行符合KVO的更改的唯一方法是通过可变代理对象 - 在NSKeyValueCoding页面中描述.这是一个非常快速的例子:
@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
}
}
Run Code Online (Sandbox Code Playgroud)