gpt4 book ai didi

swift - 只有继承自 NSObject 的类才能声明为 @objc

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:04:26 26 4
gpt4 key购买 nike

我必须通过字符串名称表示形式为属性设置值。

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(如答案中所述)

最佳答案

文档

Swift without the Objective-C Runtime: Swift on Linux does not depend on the Objective-C runtime nor includes it. While Swift was designed to interoperate closely with Objective-C when it is present, it was also designed to work in environments where the Objective-C runtime does not exist.

https://swift.org/blog/swift-linux-port/

这是明确的,只要它声明:

value of type 'A' has no member 'setValue'

基本说明底层没有KVC机制。 setValue 方法来自 Objective-C 运行时,Linux 上没有。因此,这是行不通的,您想要完成的事情根本不可能。

除此之外,以下规则适用于具有 Obj-C 运行环境的系统:


Key-Value Coding with Swift

Swift objects that inherit from NSObject or one of its subclasses are key-value coding compliant for their properties by default. Whereas in Objective-C, a property’s accessors and instance variables must follow certain patterns, a standard property declaration in Swift automatically guarantees this. On the other hand, many of the protocol’s features are either not relevant or are better handled using native Swift constructs or techniques that do not exist in Objective-C. For example, because all Swift properties are objects, you never exercise the default implementation’s special handling of non-object properties.

还有:Requiring Dynamic Dispatch

Swift APIs that are callable from Objective-C must be available through dynamic dispatch. However, the availability of dynamic dispatch doesn’t prevent the Swift compiler from selecting a more efficient dispatch approach when those APIs are called from Swift code.

You use the @objc attribute along with the dynamic modifier to require that access to members be dynamically dispatched through the Objective-C runtime. Requiring this kind of dynamic dispatch is rarely necessary. However, it is necessary when using APIs like key–value observing or the method_exchangeImplementations function in the Objective-C runtime, which dynamically replace the implementation of a method at runtime.

Declarations marked with the dynamic modifier must also be explicitly marked with the @objc attribute unless the @objc attribute is implicitly added by the declaration’s context. For information about when the @objc attribute is implicitly added, see Declaration Attributes in The Swift Programming Language (Swift 4).


为了与 KVO 兼容,元素也必须声明为动态的(对于 KVC,从 NSObject 继承就足够了):

@objc dynamic var x:String = ""

如果 String 无法解决问题,请尝试使用 NSString

如果两者都没有帮助,这似乎是 Linux 特有的问题,它似乎不支持 KVC/KVO 机制(这也是可以理解的)。

附言使用提供的代码,您的问题也在 Mac 上的 Xcode 中重现。

关于swift - 只有继承自 NSObject 的类才能声明为 @objc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46849486/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com