class 'ViewController' has no initializers ?

j'ai une erreur "class 'ViewController' has no initializers ?"


 


Je suppose que c'est un TextField qui n'a pas d'@IBOutlet, vu tout ce que j'ai bricolé...


 


J'ai tout recensé au mieux, comment pister le coupable ?


Réponses

  • Il faut voir si toutes les propriétés de ta classe ont une valeur par défaut.


  • CéroceCéroce Membre, Modérateur

    j'ai une erreur "class 'ViewController' has no initializers ?"

    Si je ne me trompe pas, on a ce message quand on a déclaré des propriétés mais qu'on ne les a pas initialisées. Le compilateur s'attend à  ce que tu ajoutes une méthode init() pour le faire.

    Tu peux également de déclarer les propriétés en !, ce qui indique que les variables ne sont pas initialisées à  l'init, mais que tu sais ce que tu fais. Notamment, c'est le cas des IBOutlets.
  • Décidément j'en apprends tous les jours, il y a 3 mois quand je m'y suis un peu remis, j'avais l'impression que je pouvais tout faire et plus j'avance, plus j'en doute...


    Quelque part je trouve ça passionnant et ne sais trop comment vous remercier.


    Les réponses sont rapides, précises ça évite de rester bloqué trop longtemps.


    J'évite quand même de poster trop vite..


    Donc merci a tous.




  • Tu peux également de déclarer les propriétés en !




     


    C'est le mal !  :D  :D  :D

  • CéroceCéroce Membre, Modérateur
    décembre 2017 modifié #6

    Décidément j'en apprends tous les jours, il y a 3 mois quand je m'y suis un peu remis, j'avais l'impression que je pouvais tout faire et plus j'avance, plus j'en doute...

    Si ça peut te rassurer, j'ai commencé mon premier projet professionnel en Swift il y a seulement trois mois. J'avais déjà  un projet perso à  mon actif, mais il n'a pas d'interface utilisateur, alors je n'avais pas eu à  m'interfacer à  UIKit.

    J'ai eu de nombreuses difficultés il y a 3 mois avec les exceptions, les optionals, les closures, les initialisations... Aujourd'hui, je me sens relativement à  l'aise. La solution est toujours la même: persévérer.

    Je sais aussi qu'il me reste encore des sujets à  approfondir: les génériques, les collections, la programmation fonctionnelle, etc. Je ne sais pas trop non plus comment fonctionne Swift sous le capot. Bref, j'ai atteint un bon niveau opérationnel, mais je ne suis pas un expert.
  • Joanna CarterJoanna Carter Membre, Modérateur
    décembre 2017 modifié #7


    C'est le mal !  :D  :D  :D




     


    Bah ouais c'est pire que ça !  ::)


     


    Il ne faut pas utiliser les ! sauf pour les IBOutlets comme :



    @IBOutlet weak var monBouton: UIButton!

    À part de ça, c'est :



    var monTruc: MonType?

    ... ou :



    var monTruc: MonTruc = MonTruc() // type explicite

    // ou

    var monInt = 123 // type déduit

    // ou

    var monString = "Swift" // type déduit

    // etc

  • CéroceCéroce Membre, Modérateur
    décembre 2017 modifié #8
    J'ai déjà  lu ici: " Vous nous dites de ne pas utiliser le !, mais le vous le faà®tes sans arrêt ". Et je trouve ça tellement vrai. Dans la vraie vie, les propriétés ! ont leur utilité. Le tout est de savoir ce qu'on fait.

    Pour les dépendances passées à  un View Controller, personnellement, je les déclare ainsi:
     
    var product: Product!
    Et j'écris:
    override func viewDidLoad() {
    assert(product != nil)
    }
    Et ça me semble pertinent parce que je vais savoir dès viewDidLoad() si j'ai oublié de fixer la dépendance, et c'est assurément un bug à  corriger.

    Alors que déclarer la dépendance en Product? rend l'erreur silencieuse, et m'oblige à  un tas de contorsions avec les optionals.
  • Absolument Céroce ! Il faut savoir faire preuve de pragmatisme en ne tombant pas dans des discours extrémistes où l'utilisation du "!" est le mal absolu. Ta proposition est par ailleurs judicieuse. 


  • J'avoue n'avoir jamais trop compris pourquoi les IBOutlets sont systématiquement "!" ?


     


    Est-ce que quelque part ça voudrait dire qu'il ne faut jamais les utiliser directement ?


  • CéroceCéroce Membre, Modérateur

    J'avoue n'avoir jamais trop compris pourquoi les IBOutlets sont systématiquement "!" ?


    On touche ici au point le plus problématique de Swift: c'est un langage qui tente d'être le plus statique possible " parce que ça permet de mieux détecter les erreurs de types et améliore les performances " mais qui doit composer avec des frameworks écrites dans un langage dynamique: Objective-C.

    Dans le cas des Outlets, elles sont fixées par Key-Value Coding (qui n'existe qu'en Objective-C). Elle ne sont pas encore fixées à  l'init, mais le sont dès qu'on arrive dans viewDidLoad(). On pourrait donc les déclarer en ?, puisqu'après-tout elles ne sont pas fixées à  tout moment, il y a donc un doute quant à  leur validité.

    Mais le choix qu'a fait Apple est le même que celui de mon exemple ci-dessus: les déclarer ! est plus pratique, ça évite de tester à  chaque fois si la propriété est nil. Et si jamais on essaie de les utiliser avant qu'elles sont fixées, on est vite au courant: ça plante.
  • Joanna CarterJoanna Carter Membre, Modérateur


    Absolument Céroce ! Il faut savoir faire preuve de pragmatisme en ne tombant pas dans des discours extrémistes où l'utilisation du "!" est le mal absolu. Ta proposition est par ailleurs judicieuse. 




     


    On n'a jamais dit que l'utilisation du ! est le mal absolu. Juste qu'il faut savoir, en l'utilisant, ce que l'on fait  :-*

  • Joanna CarterJoanna Carter Membre, Modérateur
    décembre 2017 modifié #13


    Pour les dépendances passées à  un View Controller, personnellement, je les déclare ainsi:

     



    var product: Product!

    Et j'écris:

    override func viewDidLoad() {
    assert(product != nil)
    }

    Et ça me semble pertinent parce que je vais savoir dès viewDidLoad() si j'ai oublié de fixer la dépendance, et c'est assurément un bug à  corriger.


    Alors que déclarer la dépendance en Product? rend l'erreur silencieuse, et m'oblige à  un tas de contorsions avec les optionals.

     




     


    Mais il faut faire attention quand même ailleurs parce qu'on pourrait toujours faire :



    product = nil

    ... après que l'on est déjà  passé par viewDidLoad()




  • Si je ne me trompe pas, on a ce message quand on a déclaré des propriétés mais qu'on ne les a pas initialisées. Le compilateur s'attend à  ce que tu ajoutes une méthode init() pour le faire.




     


    Je ne connaissais pas la méthode init() qu'il faut déclarer directement pour calmer Xcode ? 


    Je veux dire func init() ne marche pas alors qu'init() fonctionne du coup les alertes s'éteignent...


     


    Mais je vois dans divers exemples que les paramètres sont réaffectés dans la fonction ?


    L'idéal n'est pas de les utiliser directement et d'affecter le résultat par exemple.


     


    Bref pas très clair tout ça, disons quid de la portée des paramètres ?

  • CéroceCéroce Membre, Modérateur
    décembre 2017 modifié #15

    Je pense qu'il faut que tu lises le chapitre de la doc Swift d'Apple qui parle de l'initialisation. Tu verras que c'est fort complexe pour les classes.


     


    D'ailleurs, je préfère ne pas répondre pour ne pas écrire de bêtises !


  • Joanna CarterJoanna Carter Membre, Modérateur
    décembre 2017 modifié #16


    D'ailleurs, je préfère ne pas répondre pour ne pas écrire de bêtises !




     


    Bah non ! si tu n'avais pas écrit sur l'assert dans viewDidLoad(), je n'avais jamais pensé d'utiliser ce truc et je n'aurais pas fait la recherche pour trouver qu'il est possible de mettre les vars ! à  nil après  :-* 


  • Joanna CarterJoanna Carter Membre, Modérateur
    décembre 2017 modifié #17


    Je ne connaissais pas la méthode init() qu'il faut déclarer directement pour calmer Xcode ? 




     


    init() n'est pas une méthode, c'est là  pour faire l'initialisation des membres d'une classe.


     


    Pour la classe UIViewController, il y a trois versions d'init :



    class UIViewController
    {
    init() { ... }

    init(nibName: String?, bundle: Bundle?) { ... }

    init?(coder: NSCoder) { ... }
    }

    Si tu veux ajouter l'initialisation de tes propres vars, tu as deux choix : faire un méthode commune pour les initialiser les vars et l'appeler d'un override de tous les inits, ou initialiser tous les vars lors de leurs déclarations.



    class ViewController : UIViewController
    {
    var nom: String

    func initCommun()
    {
    nom = ""
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)
    {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

    initCommun()
    }

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

    initCommun()
    }
    }

    ... ou :



    class ViewController : UIViewController
    {
    var nom: String = ""
    }

    // ou

    class ViewController : UIViewController
    {
    var nom = ""
    }
  • ça ne répond pas a la question sur la portée.

  • Joanna CarterJoanna Carter Membre, Modérateur

    Pourquoi pas ?


  • Ben, le paramètre et sa valeur restent-ils en mémoire dans la classe, je veux dire en dehors de la fonction init() ?
  • Joanna CarterJoanna Carter Membre, Modérateur

    Si les vars sont déclarées dehors l'init() mais elles sont initialisées dans l'init(), elles restent en mémoire après.


  • GercofisGercofis Membre
    décembre 2017 modifié #22

    Pour finir sur cette partie du sujet il faut appeler la fonction init(typeParam: monParam.......)

    moninstance = moninstance.maClasse(typeParam: monParam,........)


    Je suppose que si la méthode init a l'attribut "requered" l'appel de la méthode init est obligatoire ?


     


    Je suppose qu'il faut utiliser TOUS les paramètres ?


     


    Pendant qu'on y est faut-il (obligatoirement) killer l'instance créée après utilisation ?



  • Return from initializer without initializing all stored properties

    J'ai le message suivant a la fin de la fonction/directive "init"


    J'ai comme l'impression que c'est la détection d'une variable de classe non initialisée ?


    Après vérification elles bien toutes utilisées a différents niveaux.


    Peut-on penser que parfois Xcode se trompe ?


    Je veux dire que parfois il ne reconnait pas telle ou telle variable/propertie qu'il suffit souvent de réécrire.


  • CéroceCéroce Membre, Modérateur
    Le compilateur Swift n'est pas exempt de bugs, mais j'y regarderais à  trois fois...



  • Return from initializer without initializing all stored properties

    J'ai le message suivant a la fin de la fonction/directive "init"


    J'ai comme l'impression que c'est la détection d'une variable de classe non initialisée ?


    Après vérification elles bien toutes utilisées a différents niveaux.


    Peut-on penser que parfois Xcode se trompe ?


    Je veux dire que parfois il ne reconnait pas telle ou telle variable/propertie qu'il suffit souvent de réécrire.


     




    Je n'ai jamais eu de pépins de ce genre. Tu ne peux pas montrer davantage de code ? Ce n'est pas facile de comprendre la nature du problème sur un simple message d'erreur.


  • class JourCouleur {
    //var couleur: String = ""
    var compteurAhp: Int = 0
    var compteurBhp: Int = 0
    var compteurAhc: Int = 0
    var compteurBhc: Int = 0
    var prixKwhc: Int = 0
    var prixKwHp: Int = 0
    var JcTotCxKw : Int = 0 //resultat du calcul
    var JcTotPlKw : Int = 0 //résultat du calcul
    var JcTotCxEuro : Float = 0 //résultat du calcul
    var JcTotPlEuro : Float = 0 //résultat du calcul
    //var date : Date
    var JcLblKwHp: UILabel
    var JcLblKwHc: UILabel
    var JcLblTotEuro: UILabel
    var JcLblTotHpEuro: UILabel
    var JcLblTotHcEuro: UILabel
    var JcLblHcEuro: UILabel
    var JcLTfCptAhp: UITextField
    var JcLTfCptBhp: UITextField
    var JcLTfCptAhc: UITextField
    var JcLTfCptBhc: UITextField

    init(PrmTxtFldCptAhp :UITextField, PrmTxtFldCptBhp :UITextField, PrmTxtFldCptAhc :UITextField, PrmTxtFldCptBhc :UITextField, PrmPrixKwhp: Int, PrmPrixKwhc: Int, PrmLblKwHc:UILabel,PrmLblKwHp: UILabel ,PrmLblTotHpEuro: UILabel,PrmLblTotHcEuro: UILabel, PrmLblTotEuro :UILabel)
    {

    let formateur = NumberFormatter()
    print("Compteur A HP",PrmTxtFldCptAhp.text!,"debut de la classe")
    self.compteurAhp = formateur.number(from: PrmTxtFldCptAhp.text!) as! Int
    print("Compteur A HP",PrmTxtFldCptBhp.text!,"debut de la classe")
    self.compteurBhp = formateur.number(from: PrmTxtFldCptBhp.text!) as! Int
    print("Compteur A HP",PrmTxtFldCptAhc.text!,"debut de la classe")
    self.compteurAhc = formateur.number(from: PrmTxtFldCptAhc.text!) as! Int
    print("Compteur A HP",PrmTxtFldCptBhc.text!,"debut de la classe")
    self.compteurBhc = formateur.number(from: PrmTxtFldCptBhc.text!) as! Int
    self.prixKwhc = PrmPrixKwhc
    self.prixKwHp = PrmPrixKwhp
    self.JcLblKwHp = PrmLblKwHp
    self.JcLblKwHc = PrmLblKwHc
    self.JcLblTotEuro = PrmLblTotEuro
    self.JcLblTotHpEuro = PrmLblTotHpEuro
    self.JcLblTotHcEuro = PrmLblTotHcEuro
    // if calculHP() && calculHC(){
    self.JcLTfCptAhp = PrmTxtFldCptAhp
    self.JcLTfCptBhp = PrmTxtFldCptBhp
    self.JcLTfCptAhc = PrmTxtFldCptAhc
    self.JcLTfCptBhc = PrmTxtFldCptBhc
    }


    Le message apparaà®t en face de la dernière accolade ....


  • CéroceCéroce Membre, Modérateur
    décembre 2017 modifié #27
    JcLblHcEuro n'est pas initialisé.

    Essaie de simplifier ta classe. Tu devrais avoir un Modèle pour faire les calculs, et le Contrôleur qui extrait les valeurs des UITextFields, et les écrit dans les UILabels.
  • Joanna CarterJoanna Carter Membre, Modérateur
    décembre 2017 modifié #28

    Et pourquoi tu passes tous les composants à  l'init d'une classe qui n'est pas une viewController ? Ou, même, si elle était un viewController ?


  • GercofisGercofis Membre
    décembre 2017 modifié #29


    JcLblHcEuro n'est pas initialisé.


    Essaie de simplifier ta classe. Tu devrais avoir un Modèle pour faire les calculs, et le Contrôleur qui extrait les valeurs des UITextFields, et les écrit dans les UILabels.




     


    Effectivement en neutralisant JcLblHcEuro Xcode se calme, il me semblait l'avoir déjà  neutralisé mais bon !!!


     




    Et pourquoi tu passes tous les composants à  l'init d'une classe qui n'est pas une viewController ? Ou, même, si elle était un viewController ?




    L'idée de départ était de faire une classe un peu générique vu que je fais 6 fois le même calcul que pour le coup j'ai réduit a 3...


     


    Vos 2 remarques sont très justifiées disons que c'était mais premiers essais de faire ma propre Classe Modèle confier le soin a celle-ci de faire les calculs passe encore mais d'afficher les valeurs non effectivement.


     


    En fait j'avais démarré avec uniquement les valeurs pour en gérer le stockage, j'ai rajouter les calculs ( pas forcément une bonne chose ! ) après j'ai rajouté l'affichage, on se laisse aller dans la fouler mais passer une labelView en paramètre n'a pas vraiment gros intérêt d'autant que de paramètres en variables les choses se compliquent a souhait, au point de ne plus afficher les bonnes valeurs dans les bons labels.


     


     


     


    Donc encore et toujours merci...


Connectez-vous ou Inscrivez-vous pour répondre.