在Swift中使用可编码扩展名更新对象属性

时间:2018-07-26 21:08:23

标签: ios json swift codable swift-extensions

首先,我已经实现了Decodable,它使用以下两个Integer值将JSON解码为多个对象:

public class ARBufferData: DecoderUpdatable {

    private var previousStation: Int
    private var numberOfElements: Int

    func update(from decoder: Decoder) throws {
    //Still needs work
    }
}

我现在想要实现的是使创建的对象可更新,以便当JSON中的值更改时(例如numberOfElements),只有相应对象中的值才会更改。我相信本指南可以使我做到这一点,但是我在实施它时遇到了麻烦:Understanding and Extending Swift 4’s Codable

这是KeyedDecodingContainer的扩展:

extension KeyedDecodingContainer {
    func update<T: DecoderUpdatable>(_ value: inout T, forKey key: Key, userInfo: Any) throws {
        let nestedDecoder = NestedDecoder(from: self, key: key)
        try value.update(from: nestedDecoder)
    }
}

之所以有用,是因为我可以在该值上设置一个属性观察器,并触发可视化的重新绘制。

如果有人能帮助我或指出正确的方向,我将不胜感激。

谢谢!

欢呼

1 个答案:

答案 0 :(得分:1)

有两种更新类的方法。第一,您自己解码每个int并进行比较。第二,为Int实现DecoderUpdatable并以它们作为参数调用container.update

public class ARBufferData: NSObject, Decodable, DecoderUpdatable {
    init(previousStation: Int, numberOfElements: Int) {
        self.previousStation = previousStation
        self.numberOfElements = numberOfElements
    }

    @objc dynamic var previousStation: Int
    @objc dynamic var numberOfElements: Int

    private enum CodingKeys: String, CodingKey {
        case previousStation, numberOfElements
    }

    public func update(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        try container.update(&previousStation, forKey: .previousStation)
        try container.update(&numberOfElements, forKey: .numberOfElements)
    }
}

extension Int: DecoderUpdatable {
    public mutating func update(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let result = try container.decode(Int.self)
        guard result != self else { return }
        self = result
    }
}

我不知道博客作者是否打算这样做。如果他这样做了,那么为基本类型生成DecoderUpdatable一致性可能是Sourcery的用例,但这不在本文的讨论范围。

在Swift4中,有一种有趣的观察方式,您可能也对此感兴趣:

let token = buffer.observe(\.numberOfElements, options: [.new, .old]) {
    object, change in
    if change.oldValue != change.newValue {
        // Act on change of buffer.numberOfElements.
    }
}

Source