2017-06-22 9 views
4

私は、WWDC 2017 FoundationのKVO観測のための話の例に非常によく似た何かを得ようとしています。私は、その話とは異なる唯一の違いは、super.init()を呼び出さなければならず、暗黙のうちに "kvo"トークンをアンラップさせなければならないということでした。WWDCトークに基づいたSwift 4(BETA 2)KVOのクラッシュ

遊び場で使用されている次

struct Node { 
    let title: String 
    let leaf: Bool 
    var children: [String: Node] = [:] 
} 

let t = Node(title:"hello", leaf:false, children:[:]) 
let k1 = \Node.leaf 
let k2 = \Node.children 
t[keyPath: k1] // returns "false" works 
t[keyPath: k2] // returns "[:]" works 

@objcMembers class MyController : NSObject { 
    dynamic var tr: Node 
    var kvo : NSKeyValueObservation! 
    init(t: Node) { 
     tr = t 
     super.init() 
     kvo = observe(\.tr) { object, change in 
      print("\(object) \(change)") 
     } 
    } 
} 


let x = MyController(t: t) 
x.tr = Node(title:"f", leaf:false, children:[:]) 
x 

このエラー:ようなものを得ることができ、誰が

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0). The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

です:また

fatal error: Could not extract a String from KeyPath Swift.ReferenceWritableKeyPath<__lldb_expr_3.MyController, __lldb_expr_3.Node>: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.45.6/src/swift/stdlib/public/SDK/Foundation/NSObject.swift, line 85

は、このエラーが表示この作業、またはこれは報告する必要があるバグですか?ここ

答えて

6

バグは、コンパイラは、あなたが言うことができますということです。

@objcMembers class MyController : NSObject { 
    dynamic var tr: Node 
    // ... 

Nodestructですので、直接のObj-Cで表現することはできません。ただし、コンパイラはまだtrdynamicとマークすることができます - @objcが必要です。 @objcMembersは、クラスメンバーのために@objcを推論しますが、Obj-Cで直接表現できるメンバーの場合はtrではありません。

実際には、コンパイラでtrdynamicとマークしてはいけません。先に進みました。filed a bug hereです。

trKVOがobj-Cランタイムが提供するメソッドのスウィズリングを、必要とし、スウィフトランタイムはないので、あなたは、それにKVOを使用するため@objc & dynamicするを必要とします。

class Node : NSObject { 

    let title: String 
    let leaf: Bool 
    var children: [String: Node] = [:] 

    init(title: String, leaf: Bool, children: [String: Node]) { 
     self.title = title 
     self.leaf = leaf 
     self.children = children 
    } 
} 

(とあなたが、もう一度あなたをWWDCのビデオを見ている場合:だからここにあなたがNodeclassを作る、とのObj-Cにtrを露出させるためにNSObjectから継承する必要がありますKVOを使用するには「、しかし)彼らは観察しているプロパティは、タイプの実際にNSObjectから継承classある

を見るでしょうあなたが与える例では、あなたが本当にKVOを必要としない - あなただけのstructとしてNodeを保つことができ、代わりにプロパティオブザーバを使用します。

struct Node { 
    let title: String 
    let leaf: Bool 
    var children: [String: Node] = [:] 
} 

class MyController : NSObject { 

    var tr: Node { 
     didSet { 
      print("didChange: \(tr)") 
     } 
    } 

    init(t: Node) { 
     tr = t 
    } 
} 
let x = MyController(t: Node(title:"hello", leaf:false, children: [:])) 
x.tr = Node(title:"f", leaf: false, children: [:]) 
// didChange: Node(title: "f", leaf: false, children: [:]) 

そしてNodeが値型であるため、didSetは、あまりにもそのプロパティを変更するためにトリガされます:それは客観的に依存してアップルによると

x.tr.children["foo"] = Node(title: "bar", leaf: false, children: [:]) 
// didChange: Node(title: "f", leaf: false, children: [ 
// "foo": kvc_in_playground.Node(title: "bar", leaf: false, children: [:]) 
// ]) 
+0

ありがとうございました。私はdidSetについて知っていたが、私は新しいKVOのものを試していた。 – possen

+0

コンパイラ以外のすべての偉大な、と文句を言っていない、我々は(おそらく出荷後に)ランタイムクラッシュを持っている – Jonny

0

、これはこの時点で意図した動作です-Cランタイム。これは私のバグレポートに対する彼らの回答であり、受け入れられた答えのポスターが何を確認したかをさらに確認します。

関連する問題