2017-05-10 19 views
1

사용자 정의 키보드를 만들고 컨테이너 패키지에 자산 (특히 trie 사전)을 작성한 다음 공유 컨테이너를 통해 키보드 확장이 시작될 때 액세스하려고합니다. . 이 문제를 해결하기 위해이 기본 클래스부터 시작합니다 :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") 
    } 
} 

위대한.

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") 

그것을 테스트하려면 : 내 공유 컨테이너를 설정하고, 나는 다음과 같은 공유 용기 (몇 가지 테스트 변수와 사용자 지정 개체를)로드 컨테이너 응용 프로그램에 대한의 ViewController의 viewDidLoad에 기능에있어 out 외에도 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 행을 주석 처리하면 문제가 없으므로 문제가있는 부분이 확실합니다. 그것이 컨테이너 앱에서 잘 작동하면 Keyboard Extension 내부에서 충돌이 발생하는 이유는 무엇입니까?

답변

1

대부분 다른 모듈에서 실행되는 질문입니다. 앱이 확장 프로그램과 다른 모듈이고 정규화 된 클래스 이름에 모듈 이름이 포함되어 있습니다. 앱에서는 AppName.Person과 같지만 확장 프로그램에서는 KeyboardExt.Person과 같습니다. NSCoding는 그 (것)들을 barfs와 일치 할 수 없다.

몇 가지 해결 방법이 있습니다. 하나는 app과 extension 모두에서 사용하는 프레임 워크를 만들고 거기에 공유 클래스를 두는 것입니다. 그러면 모듈 이름은 항상 'FrameworkName.Person`과 같을 것이고 모든 것이 작동 할 것입니다.

다른 하나는 특별히 (un) 아카이브 프로세스에 클래스에 사용할 이름을 지정하는 것입니다. 그런 다음 지정한 이름을 작성하고 해당 클래스와 일치시킵니다. 데이터를 쓰기 전에, 그런 다음 데이터를 읽기 전에

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

그런 짓을 반대 할 : 이것은 매우 유망한 보이는

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

-이 주사를 줄 것이다! – asetniop

+0

@asetniop 당신은 내 웹 사이트와 트위터를 통해 저에게 연락을했습니다. 도움이 되었다면 동의로 표시하십시오. 그렇지 않다면 문제가 무엇인지 설명하십시오. –

+0

그랬어! (미안해 천천히 - 내 아내가 퇴적물을 위해 맥북을 필요로했다.) 정말 고마워! – asetniop