web-dev-qa-db-fra.com

Comment créer un initialiseur personnalisé pour une sous-classe UIViewController dans Swift?

Toutes mes excuses si cela a déjà été demandé, j'ai beaucoup cherché et beaucoup de réponses sont tirées des versions antérieures de Swift Beta lorsque la situation était différente. Je n'arrive pas à trouver une réponse définitive.

Je veux sous-classe UIViewController et avoir un initialiseur personnalisé pour me permettre de le configurer facilement. J'ai du mal à faire ça à Swift.

Je veux une fonction init() que je puisse utiliser pour transmettre une NSURL spécifique que je vais ensuite utiliser avec le contrôleur de vue. Dans mon esprit, cela ressemble à quelque chose comme init(withImageURL: NSURL). Si j'ajoute cette fonction, il me demande ensuite d'ajouter la fonction init(coder: NSCoder).

Je pense que c’est parce qu’il est marqué dans la superclasse avec le mot clé required? Je dois donc le faire dans la sous-classe? Je l'ajoute:

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

Maintenant quoi? Mon initialiseur spécial est-il considéré comme un convenience? Un désigné? Est-ce que j'appelle un super initialiseur? Un initialiseur de la même classe?

Comment puis-je ajouter mon initialiseur spécial à une sous-classe UIViewController?

63
Doug Smith
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)
    }
}
116
ylin0x81

Les initialiseurs de commodité sont secondaires et supportent des initialiseurs pour un. classe. Vous pouvez définir un initialiseur de commodité pour appeler un .__ désigné. initialiseur de la même classe que l’initialiseur de confort avec certains paramètres de l’initialiseur désigné sont réglés sur les valeurs par défaut . Vous pouvez également définir un initialiseur de commodité pour créer une instance de cette classe pour un cas d'utilisation spécifique ou un type de valeur d'entrée.

Ils sont documentés ici .

4
Vatsal Manot

Pour ceux qui écrivent UI en code

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
Sasan Soroush

Si vous avez besoin d'un init personnalisé pour un popover par exemple, vous pouvez utiliser l'approche suivante: 

Créez un init personnalisé qui utilise le super init avec nibName et bundle puis accédez à la propriété view pour forcer le chargement de la hiérarchie des vues. 

Ensuite, dans la fonction viewDidLoad, vous pouvez configurer les vues avec les paramètres transmis lors de l'initialisation. 

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)
}
0
rockdaswift