【问题标题】:KVObserving a protocol in Swift 4KVO 在 Swift 4 中观察协议
【发布时间】:2017-11-09 10:51:46
【问题描述】:

我正在努力使用 Swift 4 中新的强类型 KVO 语法来观察仅通过协议可见的属性:

import Cocoa

@objc protocol Observable: class {
    var bar: Int { get }
}

@objc class Foo: NSObject, Observable {
    @objc dynamic var bar = 42
}

let implementation = Foo()

let observable: Observable = implementation

let observation = observable.observe(\.bar, options: .new) { _, change in
    guard let newValue = change.newValue else { return }

    print(newValue)
}

implementation.bar = 50

error: value of type 'Observable' has no member 'observe'
let observation = observable.observe(\.bar, options: .new) { _, change in

显然,Observable 不是NSObject。但是我不能简单地将它转换为NSObject,因为keypath的类型与对象的类型不匹配。

我尝试更明确地说明类型:

let observable: NSObject & Observable = implementation

但是:

error: member 'observe' cannot be used on value of protocol type 'NSObject & Observable'; use a generic constraint instead
let observation = observable.observe(\.bar, options: .new) { _, change in

我试图做的事情是不可能的吗?这似乎是一个常见的用例。使用旧的#keypath 语法很容易完成。你能提供任何替代方案吗?谢谢。

【问题讨论】:

  • 您的问题解决了吗?我有同样的:-(
  • 我还没解决。

标签: swift4 key-value-observing swift-protocols


【解决方案1】:

此代码在 Swift 4.1.2 (Xcode 9.4) 中编译和运行:

import Foundation

@objc protocol Observable: AnyObject {
    var bar: Int { get }
}

@objc class Foo: NSObject, Observable {
    @objc dynamic var bar = 42
}

let implementation = Foo()

let observable: NSObject & Observable = implementation

func observeWrapper<T: NSObject & Observable>(_ object: T) -> NSKeyValueObservation {
    return object.observe(\.bar, options: .new) { _, change in
        guard let newValue = change.newValue else { return }
        print(newValue)
    }
}

let observation = observeWrapper(observable)
implementation.bar = 50
withExtendedLifetime(observation, {})

我所做的只是将对observe 的调用封装在一个限制为NSObject &amp; Observable 的通用函数中。

尽管引入了泛型,但仍然可以将协议类型的 observable 传递给这个新函数。老实说,我真的无法解释为什么会这样。

编辑:这可以解释它:protocols in Swift generally don't conform to themselves,因此即使约束匹配,也不允许调用具有存在(协议类型)的泛型函数。但是@objc 协议有一个例外(没有静态要求),它确实符合自己的要求。我想这是可行的,因为Observable 被标记为@objc

【讨论】:

  • 如果你需要用@objc标记类中的每个属性,如果你在类本身上使用@objcMembers修饰符会更优雅。
  • 谢谢奥莱;您的方法确实对问题有所了解。距离可行的解决方案还有很长的路要走,因为如果我们只有Observable 开始,它需要强制转换as! (NSObject &amp; Observable)。而且我想不出任何方法来传递密钥路径,因为KeyPath&lt;Observable, Value&gt;KeyPath&lt;NSObject &amp; Observable, Value&gt; 不同。
猜你喜欢
  • 1970-01-01
  • 2018-04-01
  • 2015-02-02
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多