关键值斯威夫特观察没有出现在数组中插入和删除 [英] Key-Value Observe in Swift not showing insertions and removals in arrays

查看:310
本文介绍了关键值斯威夫特观察没有出现在数组中插入和删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了包含一个数组类。我添加了一个观察员在视图控制器阵列,并进行一些修改该数组。

I created a class which contains an array. I added an observer to that array in a view controller and performed some modifications to that array.

问题是,当我打印的observeValueForKeyPath()方法返回的变化字典,我只能看到一种NSKeyValueChangeSetting的变化。换句话说,该方法告诉我的阵列已经改变了,给我提供了新老阵列(包含所有元素),但我想收到其中添加或移除特定项目的信息。

The problem is that when I print the change dictionary returned by the observeValueForKeyPath() method I can only see changes of kind NSKeyValueChangeSetting. In other words, the method tells me the array has changed, provides me with the old and new arrays (containing all elements) but I would like to receive the information of which specific items were added or removed.

下面是一些例子code。

Here is some example code.

这是他们的数组将被观察到的类。

This is the class whose array will be observed.

private let _observedClass = ObservedClass()

class ObservedClass: NSObject {
    dynamic var animals = [String]()
    dynamic var cars = [String]()

    class var sharedInstance: ObservedClass {
        return _observedClass
    }
}

这是我的看法控制器code。

And this is the code at my view controller.

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)
    }
}

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

When I run the above code, I get this result on the console:

[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

Shouldn't, on this example, the change dictionary show each new item as it is added to the array, using the change kind NSKeyValueChangeInsertion?

推荐答案

据雨燕指南:

对于数组,仅复制发生,当你执行有权修改数组的长度潜在的动作。这包括追加,插入或取出物品,或使用一个远程标替换范围数组中的项目。

For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array.

以一个例子是追加操作。引擎盖下,当你追加到您的阵列,斯威夫特创建一个存储器阵列,复制项目从现有的动物数组到这个新阵列 - 加上新项目 - 然后分配此新的数组到动物变量。这种花招的手就是为什么你永远只得到什么样的 1 设置),因为其实每个'的修改的'实际上会导致正在创建一个新的数组。

Take as an example an append operation. Under the hood, when you append to your array, Swift creates a new array in memory, copies the items from the existing animals array into this new array - plus the new item - then assigns this new array to the animals variable. This sleight-of-hand is why you only ever get the kind of 1 (Setting), because in fact each 'edit' actually results in a new array being created.

这是一个与的NSMutableArray 不同的,因为行为是一个比较直观的 - 编辑的现有阵列构成,(有没有幕后任何─场景复制到一个新的数组),所以编辑后存在数组是之前存在的同一个阵列 - 因此存储在变化值词典与键 NSKeyValueChangeKindKey .Insertion .Removal 等一

It's different with NSMutableArray because the behaviour is a bit more intuitive - edits are made to the existing array (there's no behind-the-scenes copying to a new array), so the array that exists after the edit is the same array that existed before it - hence the value stored in the change dictionary with the key NSKeyValueChangeKindKey can be one of .Insertion, .Removal, etc.

,然而这并不是故事的全部然而,由于你的方式做一个志愿遵循的改变到的NSMutableArray 取决于您是否使用雨燕或Objective- C。在Objective-C,苹果公司强烈建议实施他们所谓的可选的<一个href=\"https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/AccessorConventions.html\"相对=nofollow>可变索引存取的。这些只是与标准签名方法,使在一个非常有效的方式符合KVO-变化。

Even that isn't the whole story however, because the way you make an KVO compliant changes to an NSMutableArray varies depending on whether you're using Swift or Objective-C. In Objective-C, Apple strongly recommend implementing what they call the optional mutable indexed accessors. These are just methods with a standard signature that make KVO-compliant changes in a very efficient way.

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

斯威夫特似乎并不拥有这些,所以唯一的办法,使符合国际志愿者组织 - 变化是通过可变的代理对象 - 在<一个描述href=\"https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueCoding_Protocol/\"相对=nofollow>的NSKeyValueCoding 页面。这里是一个非常简单的例子:

Swift doesn't appear to have these, so the only way to make KVO-compliant changes is via the mutable proxy object - described in the NSKeyValueCoding page. Here's a very quick example:

@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
    }
}

这篇关于关键值斯威夫特观察没有出现在数组中插入和删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆