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

时间:2015-03-17 00:32:55

标签: ios arrays swift key-value-observing

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

问题是当我打印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来显示添加到数组中的每个新项目吗?

1 个答案:

答案 0 :(得分:12)

根据Swift指南:

  

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

append操作为例。在引擎盖下,当你附加到你的数组时,Swift会在内存中创建一个 new 数组,将现有animals数组中的项目复制到这个新数组中 - 加上新项目 - 然后分配这个新数组到animals变量。这就是为什么你只得到1Setting)的原因,因为实际上每个' edit '实际上都会导致创建一个新的数组

它与NSMutableArray不同,因为行为更直观 - 编辑 对现有数组进行编辑(没有幕后复制到新数组),所以编辑后存在的数组与之前存在的数组相同 - 因此存储在change字典中且密钥为NSKeyValueChangeKindKey的值可以是.Insertion之一,{{1}等等。

然而,即使这不是整个故事,因为根据您使用的是Swift还是Objective-C,将KVO兼容更改为.Removal的方式会有所不同。在Objective-C中,Apple强烈建议实现他们所谓的可选mutable indexed accessors。这些只是具有标准签名的方法,可以非常有效地进行符合KVO的更改。

NSMutableArray

Swift似乎没有这些,因此进行KVO兼容更改的唯一方法是通过NSKeyValueCoding页面中描述的可变代理对象。这是一个非常简单的例子:

// 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];
}