Как создать пользовательский инициализатор для подкласса UIViewController в Swift?
Извините, если это было задано раньше, я много раз искал много, и многие ответы были получены из более ранних блайндов Swift, когда все было по-другому. Я не могу найти окончательного ответа.
Я хочу подклассом UIViewController
и иметь пользовательский инициализатор, чтобы я мог легко настроить его в коде. У меня проблемы с этим в Swift.
Мне нужна функция init()
, которую я могу использовать для передачи определенного NSURL
, который я буду использовать с контроллером представления. На мой взгляд, это выглядит как init(withImageURL: NSURL)
. Если я добавлю эту функцию, она попросит меня добавить функцию init(coder: NSCoder)
.
Я считаю, что это связано с тем, что он был отмечен в суперклассе ключевым словом required
? Так что я должен сделать это в подклассе? Я добавляю его:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Теперь что? Мой специальный инициализатор считается a convenience
one? Назначенный? Я могу назвать супер инициализатор? Инициализатор из того же класса?
Как добавить свой специальный инициализатор в подкласс UIViewController
?
Ответы
Ответ 1
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)
}
}
Ответ 2
Для тех, кто пишет интерфейс в коде
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")
}
}
Ответ 3
Удобные инициализаторы являются вторичными, поддерживающими инициализаторы для класс. Вы можете определить удобный инициализатор для вызова назначенного инициализатор из того же класса, что и удобный инициализатор с некоторые из назначенных параметров инициализаторов установлены в значения по умолчанию. Вы также можете определить удобный инициализатор для создания экземпляра этот класс для конкретного варианта использования или типа входного значения.
Они задокументированы здесь.
Ответ 4
Это очень похоже на другие ответы, но с некоторым объяснением. Принятый ответ вводит в заблуждение, потому что его свойство является необязательным и не раскрывает тот факт, что ваш init?(coder: NSCoder)
ДОЛЖЕН инициализировать каждое свойство, и единственное решение, которое имеет fatalError()
. Это значит, что вы можете обойтись без дополнительных свойств, но это не дает точного ответа на вопрос OP.
// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewController
class ViewController: UIViewController {
let name: String
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
}
// I don't have a nib. It 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 just best to leave it as 'fatalError()'
required init?(coder aDecoder: NSCoder) {
fatalError("I WILL NEVER instantiate through storyboard! It impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter")
}
}
Вы в основном должны отказаться от загрузки его из раскадровки. Почему?
Потому что, когда вы вызываете viewController storyboard.instantiateViewController(withIdentifier: "viewController")
, СИСТЕМА сделает свое дело и вызовет
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Вы никогда не сможете перенаправить этот вызов другому методу init. Тем не менее, для программно созданных viewController или nib созданных viewControllers вы можете перенаправить этот вызов, как показано выше.
Ответ 5
Если вам нужен пользовательский init для поповера, например, вы можете использовать следующий подход:
Создайте пользовательский init, который использует super init с nibName и bundle, и после этого получите доступ к свойству view для принудительной загрузки иерархии view.
Затем в функции viewDidLoad вы можете настроить представления с параметрами, переданными при инициализации.
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)
}