2017-01-07 64 views
1

我正在使用Swift操場使用NSCoding編寫父 - 子關係。Swift NSCoding - 如何讀取編碼數組

的關係可以描述爲:

One Author can write many Books

但是,它會導致一個錯誤,當我試圖保存的藏書;

Playground execution aborted: 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.

我的斯威夫特操場代碼如下;

// Author model 
class Author: NSObject, NSCoding 
{ 
    var name: String 
    var books:[Book] = [Book]() 

    init(name:String, books:[Book]?) { 
     self.name = name 
     guard let bookList = books else { 
      return 
     } 
     self.books = bookList 
    } 

    required convenience init?(coder aDecoder: NSCoder) { 
     let name = aDecoder.decodeObject(forKey:"name") as! String 
     let books = aDecoder.decodeObject(forKey:"books") as! [Book] 

     self.init(name:name, books:books) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(name, forKey:"name") 
     aCoder.encode(books, forKey:"books") 
    } 

} 

// Book model 
class Book: NSObject, NSCoding { 
    var title: String 
    var author: Author? 

    init(title:String, author: Author?) { 
     self.title = title 
     self.author = author 
    } 

    public convenience required init?(coder aDecoder: NSCoder) { 

     let title = aDecoder.decodeObject(forKey: "title") as! String 
     let author = aDecoder.decodeObject(forKey: "author") as! Author 

     self.init(title:title, author:author) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(title, forKey: "title") 
     aCoder.encode(author, forKey: "author") 
    } 
} 

// Create the data 
var author:Author = Author(name: "Tom Clancy", books: nil) 
let book0 = Book(title: "The Hunt for Red October", author: author) 
let book1 = Book(title: "Red Storm Rising", author: author) 
author.books.append(contentsOf: [book0, book1]) 

// ----------- 
// Save data 

let manager = FileManager.default 
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first! as URL 
let writePath: URL = url.appendingPathComponent("archive.plist") 

print("Attempting to save to: \(writePath)") 

let saveData = NSMutableData() 

let archiver = NSKeyedArchiver(forWritingWith: saveData) 
archiver.encode(books, forKey:"books") 
archiver.encode(author, forKey: "author") 
//NSKeyedArchiver.archiveRootObject(books, toFile: writePath.path) 
archiver.finishEncoding() 

_ = saveData.write(to: writePath, atomically: true) 


// ----------- 
// Load data 

print("Attempting to load from: \(writePath)") 

if FileManager.default.fileExists(atPath: writePath.path) { 
    if let saveData = try? Data(contentsOf: writePath) { 
     let unarchiver = NSKeyedUnarchiver(forReadingWith: saveData) 

// Crash occurs here 
      var authorData = unarchiver.decodeObject(forKey: "author") as! Author 
print (authorData.name) 


    } 
} else { 
    print("No data archive exists") 
} 

所以我的問題是:什麼是導致錯誤,我該如何糾正這個問題?

非常感謝

回答

1

我能夠通過重構我的代碼來解決這個問題。

class Author: NSObject, NSCoding 
{ 
    var name: String 
    var books:[Book] = [Book]() 

    init(name:String, books:[Book]?) { 
     self.name = name 
     guard let bookList = books else { 
      return 
     } 
     self.books = bookList 
    } 

    required convenience init?(coder aDecoder: NSCoder) { 
     let name = aDecoder.decodeObject(forKey:"name") as! String 
     let books = aDecoder.decodeObject(forKey:"books") as! [Book] 

     self.init(name:name, books:books) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(name, forKey:"name") 
     aCoder.encode(books, forKey:"books") 
    } 

} 

class Book: NSObject, NSCoding { 
    var title: String 
    var author: Author 

    init(title:String, author: Author) { 
     self.title = title 
     self.author = author 
    } 

    public convenience required init?(coder aDecoder: NSCoder) { 

     let title = aDecoder.decodeObject(forKey: "title") as! String 
     let author = aDecoder.decodeObject(forKey: "author") as! Author 

     self.init(title:title, author:author) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(title, forKey: "title") 
     aCoder.encode(author, forKey: "author") 
    } 
} 

let author:Author = Author(name: "Tom Clancy", books: nil) 
let books = [ 
    Book(title: "The Hunt for Red October", author: author) 
    , Book(title: "Red Storm Rising", author: author) 
] 
//author.books.append(contentsOf: books) 


// ----------- 
// Save data 


let manager = FileManager.default 
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first! as URL 
let writeFile: URL = url.appendingPathComponent("books.data") 

print ("Attempting to write to: \(writeFile.path)") 

NSKeyedArchiver.archiveRootObject(books, toFile: writeFile.path) 

if let bookData = NSKeyedUnarchiver.unarchiveObject(withFile: writeFile.path) as? [Book] { 
    for book in bookData { 
     print ("\(book.title) - \(book.author.name)") 
    } 
} 

這似乎工作。

Issue closed