簡體   English   中英

無法弄清楚編碼器 aDecoder: NSCoder

[英]Can't figure out coder aDecoder: NSCoder

我正在制作一個用於歸檔書籍的應用程序,我正在連接一個按鈕來保存數據,但我無法通過初始化。

這是Xcode給我的錯誤:

Property 'self.bookStore' not initialised at super.init call.

這是我的代碼:

import UIKit

class AddBook: UIViewController {

    @IBOutlet weak var bookAuthor: UITextField!
    @IBOutlet weak var bookTitle: UITextField!

    let bookStore: BookStore

    init(bookStore: BookStore) {
        self.bookStore = bookStore
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder) // Error: Property 'self.bookStore' not initialised at super.init call.
    }


    @IBAction func saveNewBook(sender: AnyObject) {
        let author = self.bookAuthor.text!
        let title = self.bookTitle.text!

        bookStore.addBook(author, title: title)
        println("\(bookStore)")
    }
}


import UIKit

class BookStore: NSObject {

    var allBooks: [Book] = []

    func addBook(author: String, title: String) -> Book {
        let newBook = Book(author: author, title: title)

        allBooks.append(newBook)

        return newBook
    }
}

您的自定義初始化程序無法初始化不可變屬性。 如果您希望它是不可變的,那么不要創建自定義初始化程序,只需在所需或指定的初始化程序之一中進行初始化。

像這樣,

class AddBook: UIViewController {

    @IBOutlet weak var bookAuthor: UITextField!
    @IBOutlet weak var bookTitle: UITextField!

    let bookStore: BookStore

    required init(coder aDecoder: NSCoder) {
        fatalError("Cannot be instantiated from storyboard")
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        bookStore = BookStore()
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }


    @IBAction func saveNewBook(sender: AnyObject) {
        let author = self.bookAuthor.text!
        let title = self.bookTitle.text!

        bookStore.addBook(author, title: title)
    }
}

或這個,

class AddBook: UIViewController {

    @IBOutlet weak var bookAuthor: UITextField!
    @IBOutlet weak var bookTitle: UITextField!

    let bookStore: BookStore

    required init(coder aDecoder: NSCoder) {
        bookStore = BookStore()
        super.init(coder: aDecoder)
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        fatalError("Cannot be instantiated from code")

    }


    @IBAction func saveNewBook(sender: AnyObject) {
        let author = self.bookAuthor.text!
        let title = self.bookTitle.text!

        bookStore.addBook(author, title: title)
    }
}

但是,在您的情況下,您希望它在使用let bookStore: BookStore 時保持不變,但是如果您不使用故事板,您可以簡單地從所需的初始化程序中拋出致命的異常並像這樣使用您自己的初始化程序,

class AddBook: UIViewController {

    @IBOutlet weak var bookAuthor: UITextField!
    @IBOutlet weak var bookTitle: UITextField!

    let bookStore: BookStore

    init(bookStore: BookStore) {
        self.bookStore = bookStore
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("cannot be initialized from storyboard")
    }

    @IBAction func saveNewBook(sender: AnyObject) {
        let author = self.bookAuthor.text!
        let title = self.bookTitle.text!

        bookStore.addBook(author, title: title)
    }
}


let book = AddBook(bookStore: BookStore())

現在,您需要擁有所需的初始化程序,您必須使屬性可變,以便您可以像這樣從自定義初始化程序設置它,

class AddBook: UIViewController {

    @IBOutlet weak var bookAuthor: UITextField!
    @IBOutlet weak var bookTitle: UITextField!

    var bookStore: BookStore!

    init(bookStore: BookStore) {
        self.bookStore = bookStore
        super.init(nibName: nil, bundle: nil)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    @IBAction func saveNewBook(sender: AnyObject) {
        let author = self.bookAuthor.text!
        let title = self.bookTitle.text!

        bookStore.addBook(author, title: title)
    }
}


let book = ... // initialized from storyboard or using performSegueWithIdentifier:

book.bookStore =  BookStore()

這里的主要理念是,沒有兩個初始化程序可以初始化不可變屬性。 只有一個人能做到,所以要么使用 required 初始化器來實例化它,要么使 required 初始化器不可用,要么使屬性可變,這樣你就可以有兩個初始化器,並且兩者都可以初始化它。

在調用 super.init 之前,必須在 init 方法中定義必需的屬性。

因此,如果您想要一個必需的 bookStore 屬性,並且想要覆蓋 init.coder 方法,則需要在調用 super.init 之前為 bookStore 分配一個值:

required init(coder aDecoder: NSCoder) 
{
   bookStore = //some value here
   super.init(coder: aDecoder) 
}

可能最簡單的做法是讓你的 bookStore 屬性成為一個可選的變量:

var bookStore: BookStore?

如果您這樣做,您將不必在初始化時為您的視圖控制器的書店屬性分配一個值,並且可以稍后在設置用於顯示的視圖控制器時進行此操作。

回到initWithCoder()

initWithCoder(或init(coder)在 Swift 中被稱為)是一種應該反序列化對象的方法。

iOS 使用 initWithCoder 從 XIB 文件和故事板中讀取界面對象。

這個想法是您編寫 initWithCoder 和 encodeWithCoder 的自定義版本,它們知道如何讀/寫對象的自定義屬性,以便將其保存到文件中。

在 encodeWithCoder 中,您編寫代碼將對象的自定義屬性作為鍵/值對保存到存檔器中。 然后在 initWithCoder 中,您使用NSKeyedUnarchiver的方法從存檔器讀取這些鍵/值對以讀取這些值。

我不明白為什么你需要 init 但規則是所有屬性在調用 super.init 之前都必須有值(bookStore 沒有)。 我認為你可以簡單地解決這個問題,就像 let bookStore = BookStore()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM