Mohon maaf jika ini telah ditanyakan sebelumnya, saya telah mencari-cari banyak dan banyak jawaban berasal dari beta Swift sebelumnya ketika semuanya berbeda. Saya tidak dapat menemukan jawaban yang pasti.
Saya ingin membuat subkelas UIViewController
dan memiliki penginisialisasi khusus untuk memungkinkan saya mengaturnya dalam kode dengan mudah. Saya mengalami masalah saat melakukan ini di Swift.
Saya ingin sebuah init()
fungsi yang dapat saya gunakan untuk melewati spesifik yang NSURL
kemudian akan saya gunakan dengan pengontrol tampilan. Dalam pikiranku itu terlihat seperti init(withImageURL: NSURL)
. Jika saya menambahkan fungsi itu kemudian meminta saya untuk menambahkan init(coder: NSCoder)
fungsi tersebut.
Saya percaya ini karena itu ditandai di superclass dengan required
kata kunci? Jadi saya harus melakukannya di subclass? Saya menambahkannya:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Sekarang apa? Apakah penginisialisasi khusus saya dianggap sebagai penginisialisasi convenience
? Yang ditunjuk? Apakah saya memanggil penginisialisasi super? Penginisialisasi dari kelas yang sama?
Bagaimana cara menambahkan penginisialisasi khusus saya ke UIViewController
subkelas?
sumber
Jawaban:
class ViewController: UIViewController { var imageURL: NSURL? // this is a convenient way to create this view controller without a imageURL convenience init() { self.init(imageURL: nil) } init(imageURL: NSURL?) { self.imageURL = imageURL super.init(nibName: nil, bundle: nil) } // if this view controller is loaded from a storyboard, imageURL will be nil /* Xcode 6 required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } */ // Xcode 7 & 8 required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } }
sumber
ViewController()
,ViewController(imageURL: url)
atau loading itu dari storyboard.required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
jika tidaksuper.init(coder: aDecoder)
saya mendapatkan kesalahan Propertiself.someProperty
tidak diinisialisasi saatsuper.init
dihubungiinit(coder: aDecoder)
. ThefatalError
akan mencukupiBagi mereka yang menulis UI dalam kode
class Your_ViewController : UIViewController { let your_property : String init(your_property: String) { self.your_property = your_property super.init(nibName: nil, bundle: nil) } override func viewDidLoad() { super.viewDidLoad() } required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") } }
sumber
Ini sangat mirip dengan jawaban lain, tetapi dengan beberapa penjelasan. Jawaban yang diterima menyesatkan karena propertinya bersifat opsional dan tidak mengungkapkan fakta bahwa
init?(coder: NSCoder)
HARUS Anda menginisialisasi setiap properti dan satu-satunya solusi untuk itu adalah memilikifatalError()
. Pada akhirnya, Anda bisa lolos dengan menjadikan properti Anda opsional, tetapi itu tidak benar-benar menjawab pertanyaan OP.// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewController class ViewController: UIViewController { let name: String override func viewDidLoad() { super.viewDidLoad() } // I don't have a nib. It's all through my code. init(name: String) { self.name = name super.init(nibName: nil, bundle: nil) } // I have a nib. I'd like to use my nib and also initialze the `name` property init(name: String, nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle? ) { self.name = name super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } // when you do storyboard.instantiateViewController(withIdentifier: "ViewController") // The SYSTEM will never call this! // it wants to call the required initializer! init?(name: String, coder aDecoder: NSCoder) { self.name = "name" super.init(coder: aDecoder) } // when you do storyboard.instantiateViewController(withIdentifier: "ViewController") // The SYSTEM WILL call this! // because this is its required initializer! // but what are you going to do for your `name` property?! // are you just going to do `self.name = "default Name" just to make it compile?! // Since you can't do anything then it's just best to leave it as `fatalError()` required init?(coder aDecoder: NSCoder) { fatalError("I WILL NEVER instantiate through storyboard! It's impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter") } }
Pada dasarnya Anda harus MENGABAIKAN memuatnya dari storyboard. Mengapa?
Karena ketika Anda memanggil viewController
storyboard.instantiateViewController(withIdentifier: "viewController")
maka UIKit akan melakukan tugasnya dan memanggilnyarequired init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
Anda tidak pernah bisa mengalihkan panggilan itu ke metode init lain.
Namun untuk viewController yang dibuat secara terprogram atau viewControllers yang dibuat nib, Anda dapat mengalihkan panggilan tersebut seperti yang ditunjukkan di atas.
sumber
Mereka didokumentasikan di sini .
sumber
Jika Anda memerlukan init kustom untuk popover misalnya, Anda dapat menggunakan pendekatan berikut:
Buat init kustom yang menggunakan super init dengan nibName dan bundle dan setelah itu akses properti view untuk memaksa pemuatan hierarki tampilan.
Kemudian dalam fungsi viewDidLoad Anda dapat mengonfigurasi tampilan dengan parameter yang diteruskan dalam inisialisasi.
import UIKit struct Player { let name: String let age: Int } class VC: UIViewController { @IBOutlet weak var playerName: UILabel! let player: Player init(player: Player) { self.player = player super.init(nibName: "VC", bundle: Bundle.main) if let view = view, view.isHidden {} } override func viewDidLoad() { super.viewDidLoad() configure() } func configure() { playerName.text = player.name + "\(player.age)" } } func showPlayerVC() { let foo = Player(name: "bar", age: 666) let vc = VC(player: foo) present(vc, animated: true, completion: nil) }
sumber