【发布时间】:2017-10-20 12:52:31
【问题描述】:
我必须通过字符串名称表示来设置属性的值。
import Foundation
@objc class A:NSObject {
var x:String = ""
}
var a = A()
a.x = "ddd"
print(a.x)
a.setValue("zzz", forKey:"x")
print(a.x)
在编译过程中出现奇怪的错误:
main.swift:4:2: error: only classes that inherit from NSObject can be declared @objc
@objc class A:NSObject {
~^~~~~
main.swift:13:1: error: value of type 'A' has no member 'setValue'
a.setValue("zzz", forKey:"x")
^ ~~~~~~~~
有人知道发生了什么吗?
PS:可在 Swift 4.0 和 3.1.1(Ubuntu 16.04.3 LTS)上重现
已编辑:
import Foundation
@objc class A:NSObject {
@objc dynamic var x:String = ""
}
var a = A()
a.x = "ddd"
print(a.x)
a.setValue("zzz", forKeyPath:"x")
print(a.x)
输出:
错误:只有继承自 NSObject 的类才能声明为@objc @objc 类 A:NSObject {
错误:属性不能被标记为@objc,因为它的类型不能在Objective-C中表示 @objc 动态变量 x:String = ""
注意:Swift 结构不能在 Objective-C 中表示 @objc 动态变量 x:String = ""
错误:“A”类型的值没有成员“setValue” a.setValue("zzz", forKeyPath:"x")
编辑 2: 就像“c-style”一样尝试:
func set<T>(_ val:T, forKey key:String) {
print("SET:\(self) \(key) to \(val)")
let ivar: Ivar = class_getInstanceVariable(type(of: self), key)!
let pointerToInstanceField:UnsafeMutableRawPointer = Unmanaged.passRetained(self).toOpaque().advanced(by: ivar_getOffset(ivar))
let pointer = pointerToInstanceField.assumingMemoryBound(to: T.self)
pointer.pointee = val
}
它运行良好,但在递归调用中会导致错误访问。可能有一些保留/释放问题。会挖北斗。也不适用于 Linux(如答案中所述)
【问题讨论】:
-
这是一个误导性错误(您可能很想提交一个错误)。问题很简单,Linux 上没有 Swift 的 Obj-C 运行时。你不能标记
@objc,也不能使用 KVC(考虑使用 Swift 键路径)。 -
@Hamish,谢谢你的建议。你能指点我一些关于 Swift 关键路径的文档吗?不能谷歌任何关于。它还需要 (at)objc 后缀。我说的对吗?
-
@jww,我的问题不是重复你的建议
-
@NickZaporozhchenko Swift 关键路径本身不需要 Obj-C 暴露;您可以在 the evolution proposal 上阅读更多关于它们的信息(您还可以通过简单搜索“Swift 4 keypath”找到许多在线资源)。