2017-05-10 3 views
1

私はカスタムキーボードを作っています。コンテナアプリケーションにアセット(具体的にはトライ辞書)を作成し、共有コンテナを使用してキーボード拡張機能を起動するとアクセスします。これまでに、私はこのかなり基本的なクラスから始めます:Swiftの共有コンテナにカスタムオブジェクトにアクセス

class Person: NSObject, NSCoding { 
    let name: String 
    let age: Int 
    init(name: String, age: Int) { 
     self.name = name 
     self.age = age 
    } 
    required init(coder decoder: NSCoder) { 
     self.name = decoder.decodeObject(forKey: "name") as? String ?? "" 
     self.age = decoder.decodeInteger(forKey: "age") 
    } 

    func encode(with coder: NSCoder) { 
     coder.encode(name, forKey: "name") 
     coder.encode(age, forKey: "age") 
    } 
} 

素晴らしいです。私はセットアップ私の共有コンテナを持っている、とコンテナアプリのためのViewControllerののviewDidLoad機能に私は(いくつかのテスト変数およびカスタム・オブジェクト)のような共有コンテナをロード:

let shared = UserDefaults(suiteName: "group.test_keyboard") 
    shared!.set("test", forKey:"key_string") 
    shared!.set(false, forKey:"key_boolean") 
    shared!.set(34, forKey:"key_int") 

    let newPerson = Person(name: "Joe", age: 10) 
    let encodedData = NSKeyedArchiver.archivedData(withRootObject: newPerson) 
    shared!.set(encodedData, forKey: "people") 

それをテストするには私はviewWillAppearに次のコードを追加しました:

let shared = UserDefaults(suiteName: "group.test_keyboard") 
    let test_string = shared?.string(forKey: "key_string") 

    if(test_string != nil){ 
     print("string-\(test_string!)") 
    } 
    else{ 
     print("nil") 
    } 

    // retrieving a value for a key 
    if let data = shared?.data(forKey: "people"){ 
     let test_person = NSKeyedUnarchiver.unarchiveObject(with: data) as? Person 
     print("-\(test_person!.name)") // Joe 

     let data_size = String(data.count) 
     print("-\(data_size)") 

    } else { 
     print("There is an issue") 
    } 

すべてが正常にチェックアウトされています。私はKeyboardViewControllerに行くと、単純な文字列を検索し、アクセスのものにしようとすると、しかし、正常に動作します:

if let data = shared?.data(forKey: "people") { 
     (textDocumentProxy as UIKeyInput).insertText("found") 

     (textDocumentProxy as UIKeyInput).insertText(String(data.count)) 

     let myPeople = NSKeyedUnarchiver.unarchiveObject(with: data) as? Person 

    } 

Iを:

let shared = UserDefaults(suiteName: "group.test_keyboard") 
    shared?.synchronize() 
    let test_string = shared?.string(forKey: "key_string") 

    if(test_string != nil){ 
     (textDocumentProxy as UIKeyInput).insertText(test_string!) 
    } 
    else{ 
     (textDocumentProxy as UIKeyInput).insertText("nil") 
    } 

をしかし、私は、次のような、カスタムオブジェクトの人にアクセスしよう以下のエラー応答でクラッシュを取得:

2017-05-10 14:34:46.938253-0700 test_keyboard[3196:857207] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}

私は両側にシンプルdata.countチェックを行うとデータがある、それは同じサイズ(269)です。私がNSKeyedUnarchiver行をコメントアウトしても問題はないので、問題がどこにあるのかは確かです。何が起こっているそれはそれがちょうどコンテナアプリでうまくいくときにキーボードエクステンション内でクラッシュする原因になりますか?

答えて

1

おそらく、それは異なるモジュールで動作することの問題です。あなたのアプリは拡張モジュールとは別のモジュールであり、完全修飾クラス名にはモジュール名が含まれています。このアプリではAppName.Personのようなものですが、拡張子はKeyboardExt.Personのようなものです。 NSCodingはそのように上に一致することはできませんので、barfs。

いくつかの回避策があります。 1つは、appとextensionの両方で使用されるフレームワークを作成し、そこに共有クラスを配置することです。その後、モジュールを持つ名前は常に 'FrameworkName.Person`のようなものになり、すべてが機能します。

もう1つは、(un)アーカイブプロセスに、そのクラスに使用する名前を明示することです。次に、あなたが指定した名前を書き、それを適切なクラスにマッチさせます。任意のデータを書き込む前に、その後、任意のデータを読む前に

NSKeyedArchiver.setClassName("Person", for: Person.self) 

ような何かを、逆の操作を行います。これは非常に有望に見える

NSKeyedUnarchiver.setClass(Person.self, forClassName: "Person") 
+0

- 私はこのショットを与えます! – asetniop

+0

@asetniopあなたは私のウェブサイトとTwitterを介して私に連絡して、これに答えるかどうか尋ねました。それが助けられたら、それを合格とマークしてください。そうでない場合は、あなたがそれを持っていた問題を記述してください。 –

+0

しました! (遅くなって申し訳ありません - 私の妻は沈殿のためにマックブックを必要としました)ありがとうございました! – asetniop

関連する問題