2017-10-20 74 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