2017-10-20 103 views
0

我必须通过字符串名称表示将值设置为属性。只能继承从NSObject继承的类@objc

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:再现的上夫特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 class A:NSObject {

错误:属性无法标记@objc,因为它的类型不能在Objective-C表示 @objc动态无功X:字符串= “”

注:迅捷结构不能在Objective-C来表示 @objc动态无功X:字符串= “”

错误:的值'A' 型有没有成员 '的setValue' a.setValue( “ZZZ”,forKeyPath: “X”)

编辑2: 只是想如 “C风格”:

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上(如在答案中提到)

+0

[如何在Objective-C中使用Swift非NSObject子类]的可能重复(https://stackoverflow.com/questions/32997550/how-to-use-swift-non-nsobject-subclass-in-objective -c) – jww

+0

这是一个误导性的错误(你可能想要提交一个错误)。问题很简单,在Linux上没有使用Swift的Obj-C运行时。你不能标记'@ objc',并且你不能使用KVC(改为使用Swift键路径)。 – Hamish

+0

@Hamish,谢谢你的建议。你能指点我一些关于Swift关键路径的文档吗?不能谷歌任何关于。它也需要(at)objc后缀。我对吗? –

回答

3

文档

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机制(这也是可以理解的)。

P.S.随着提供的代码,您的问题也在Mac上的Xcode中重现。

+0

刚刚尝试 - 没有成功。还添加了新的错误:1:属性不能被标记@objc,因为它的类型不能在Objective-C中表示; 2:Swift结构不能用Objective-C –

+0

表示尝试将它定义为'NSString' – Hexfire

+0

除此之外,它有点令人惊讶。 '字符串类型与Objective-C类NSString桥接,并提供与C函数的互操作性,可用于字符串。' – Hexfire