Подтвердить что ты не робот

Как создать пользовательский инициализатор для подкласса 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?

4b9b3361

Ответ 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)
}