Приносим извинения, если об этом спрашивали раньше, я много искал, и многие ответы взяты из более ранних бета-версий Swift, когда все было иначе. Кажется, я не могу найти однозначного ответа.
Я хочу UIViewController
создать подкласс и иметь собственный инициализатор, который позволит мне легко настроить его в коде. У меня проблемы с этим в Swift.
Мне нужна init()
функция, которую я могу использовать для передачи конкретной функции, которую NSURL
я затем использую с контроллером представления. На мой взгляд, это выглядит примерно так init(withImageURL: NSURL)
. Если я добавлю эту функцию, он попросит меня добавить эту init(coder: NSCoder)
функцию.
Я считаю, что это потому, что он отмечен в суперклассе required
ключевым словом? Значит, я должен сделать это в подклассе? Добавляю:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Что теперь? Считается ли мой специальный инициализатор единичным convenience
? Назначенный? Я вызываю суперинициализатор? Инициализатор из того же класса?
Как мне добавить свой специальный инициализатор в UIViewController
подкласс?
источник
Ответы:
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) } }
источник
ViewController()
,ViewController(imageURL: url)
или загрузить его из раскадровки.required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
иначеsuper.init(coder: aDecoder)
я получал ошибку « Свойствоself.someProperty
не инициализировано приsuper.init
вызове»init(coder: aDecoder)
.fatalError
ХВАТИТДля тех, кто пишет UI в коде
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") } }
источник
Это очень похоже на другие ответы, но с некоторыми пояснениями. Принятый ответ вводит в заблуждение, потому что его свойство является необязательным и не раскрывает тот факт, что вы
init?(coder: NSCoder)
ДОЛЖНЫ инициализировать каждое свойство, и единственное решение для этого - наличиеfatalError()
. В конечном итоге вы могли бы уйти, сделав свои свойства необязательными, но это не полностью отвечает на вопрос 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") } }
Вы в основном должны отказаться от загрузки из раскадровки. Зачем?
Потому что , когда вы вызываете ViewController
storyboard.instantiateViewController(withIdentifier: "viewController")
тогда UIKit будет делать свое дело и вызовrequired init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
Вы никогда не сможете перенаправить этот вызов другому методу инициализации.
Тем не менее, для программно созданных viewController или созданных пером viewController вы можете перенаправить этот вызов, как показано выше.
источник
Они задокументированы здесь .
источник
Например, если вам нужен собственный init для всплывающего окна, вы можете использовать следующий подход:
Создайте пользовательский init, который использует super init с nibName и bundle, и после этого обратитесь к свойству представления, чтобы принудительно загрузить иерархию представления.
Затем в функции 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) }
источник