Xcode 9 Swift 4 - 'init(_: NSNumber)' is deprecated pour Double

Bonjour à  tous


 


J'ai des warnings un peu partout dans Xcode 9 lorsque je compile mon app.


 


Voici un exemple :



self.altitudeEnMetres = Double(data!.relativeAltitude) 'init' is deprecated

Ca vous dit quelque chose ?


 


Merci


 


Réponses

  • merci, j'ai utilisé cela : 



    self.altitudeEnMetres = (data!.relativeAltitude).doubleValue

    j'aimerais bien comprendre pourquoi ce changement ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    juin 2017 modifié #4

    Ce n'est pas init() globalement qui est deprecated, c'est seulement la version sans nom de paramètre qui est deprecated pour Double pour le type (NSNumber ?) que tu passes comme paramètre.


     


    Si relativeAltitude est un NSNumber, il faut :



    self.altitudeEnMetres = Double(exactly: data!.relativeAltitude)

    Mais n'oublies pas que cet variant renvoie un Double? (optionnel).


     


    N'importe comment tu te débrouilles sur l'init, tu devrais éviter d'utiliser le '!' comme ça.


     


    Tu es sûr que data ne peux jamais être à  nil ?


  • macphimacphi Membre
    juin 2017 modifié #5

    Effectivement je risque de tuer un poney...


    ;-)


     


    Voici l'ensemble du code :



    if CMAltimeter.isRelativeAltitudeAvailable() {
    altimeter.startRelativeAltitudeUpdates(to: OperationQueue.main, withHandler: { data, error in
    if !(error != nil)
    self.altitudeEnMetres = (data!.relativeAltitude).doubleValue
    self.altitudeEnMetres = Double(exactly: data!.relativeAltitude)
    self.altitudeEnPied = self.altitudeEnMetres * 3.28084
    self.relativeAltitude.text = String(format:"%.2f ft", self.altitudeEnPied) + " / " + String(format:"%.2f m", self.altitudeEnMetres)
    self.pressionEnHPA = (data!.pressure).doubleValue
    self.pressionEnHPA = self.pressionEnHPA * 10
    self.pressionHELLO = Double(self.pressionEnHPA * 0.750062)
    self.pressionMM = String(format:"%.2f mm", self.pressionHELLO)
    self.pressure2.text = String(format:"%.2f hPa", self.pressionEnHPA) + " - " + self.pressionMM
    }
    })
    }

    Je me suis dit que le "if CMAltimeter.isRelativeAltitudeAvailable()" pouvais me préserver d'un data à  nil non ?


    Ou alors je fais du if let ?


     


    Je suis preneur, comme amateur, de tous les conseils...

  • Joanna CarterJoanna Carter Membre, Modérateur
    juin 2017 modifié #6


    Effectivement je risque de tuer un poney...


    ;-)


     


    Voici l'ensemble du code :



    if CMAltimeter.isRelativeAltitudeAvailable() {
    altimeter.startRelativeAltitudeUpdates(to: OperationQueue.main, withHandler: { data, error in
    if !(error != nil)
    self.altitudeEnMetres = (data!.relativeAltitude).doubleValue
    self.altitudeEnMetres = Double(exactly: data!.relativeAltitude)
    self.altitudeEnPied = self.altitudeEnMetres * 3.28084
    self.relativeAltitude.text = String(format:"%.2f ft", self.altitudeEnPied) + " / " + String(format:"%.2f m", self.altitudeEnMetres)
    self.pressionEnHPA = (data!.pressure).doubleValue
    self.pressionEnHPA = self.pressionEnHPA * 10
    self.pressionHELLO = Double(self.pressionEnHPA * 0.750062)
    self.pressionMM = String(format:"%.2f mm", self.pressionHELLO)
    self.pressure2.text = String(format:"%.2f hPa", self.pressionEnHPA) + " - " + self.pressionMM
    }
    })
    }

    Je me suis dit que le "if CMAltimeter.isRelativeAltitudeAvailable()" pouvais me préserver d'un data à  nil non ?




     


    Bah non !  ::)  Si tu regardes les paramètres du closure, tu verrais que data et error sont tous les deux optionnels.



    let altimeter = CMAltimeter()

    var altitudeEnMetres: Double = 0.0

    var altitudeEnPied: Double
    {
    return altitudeEnMetres * 3.28084
    }

    var pressionEnHpa: Double = 0.0

    var pressionEnMm: Double
    {
    return pressionEnHpa * 0.750062
    }

    @IBOutlet weak var relativeAltitudeLabel: UILabel!

    @IBOutlet weak var pressionMmLabel: UILabel!

    @IBOutlet weak var pressionHpaLabel: UILabel!

    ...



    if CMAltimeter.isRelativeAltitudeAvailable()
    {
    altimeter.startRelativeAltitudeUpdates(to: .main, withHandler:
    {
    [unowned self] (data: CMAltitudeData?, error: Error?) in

    if error != nil
    {
    // afficher un message pour l'erreur

    return
    }

    guard let data = data else
    {
    return
    }

    self.altitudeEnMetres = data.relativeAltitude.doubleValue

    self.relativeAltitudeLabel.text = String(format: "%.2 ft / %.2 m", self.altitudeEnPied, self.altitudeEnMetres)

    self.pressionEnHpa = data.pressure.doubleValue * 10

    self.pressionMmLabel.text = String(format: "%.2f hPa - %.2f mm", self.pressionEnHpa, self.pressionEnMm)
    })
    }

  • Merci pour la leçon de code !


     


    Du coup en prenant modèle son ton code, j'ai quelques autres modifications à  faire ailleurs...


     


    o:)  



  • [unowned self] (data: CMAltitudeData?, error: Error?) in

    Euh, c'est vraiment la bonne syntaxe, nounours ?

  • Joanna CarterJoanna Carter Membre, Modérateur
    C'est une des bonnes
  • On peut mélanger une formulation Objective-C avec du Swift  ?

  • CéroceCéroce Membre, Modérateur
    juin 2017 modifié #11

    On peut mélanger une formulation Objective-C avec du Swift  ?


    Ce n'est pas une formulation Objective-C, c'est une "Capture List". Les crochets indiquent les attributs des paramètres de la closure. Par exemple, il est courant d'utiliser [weak self].
    Voir https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID544
  • DrakenDraken Membre
    juin 2017 modifié #12

    Oki. Merci. J'ignorais. A chaque jour sa petite pierre de connaissance !


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

    En utilisant :



    [unowned self] (data: CMAltitudeData?, error: Error?) in

    J'ai déclaré que je veux "capter" self en évitant de faire une référence circulaire.


     


    Normalement, on utilise 'unowned' pour self ou 'weak' pour les vars externes ; mais il faut lire les docs pour mieux déterminer lequel.


     


    Et, avec ce code ci-dessus, j'ai déclaré explicitement les types des paramètres pour les montrer à  macphi.


     


    Il n'est pas obligatoire de déclarer les types si on les connais bien et, dans ce cas là , on peut oublier les parentheses :



    [unowned self] data, error in

    Et, si on voulait avoir l'air ultra-cool (et confondre ses collègues au même temps, on peut faire :



    altimeter.startRelativeAltitudeUpdates(to: .main, withHandler:
    {
    [unowned self] in

    if $1 != nil
    {
    // afficher un message pour l'erreur

    return
    }

    guard let data = $0 else
    {
    return
    }

    ...

    ::)  8--)  >:D




  • Et, si on voulait avoir l'air ultra-cool (et confondre ses collègues au même temps, on peut faire :



    altimeter.startRelativeAltitudeUpdates(to: .main, withHandler:
    {
    [unowned self] in

    if $1 != nil
    {
    // afficher un message pour l'erreur

    return
    }

    guard let data = $0 else
    {
    return
    }

    ...

    ::)  8--)  >:D




    La première version est nettement plus lisible...

  • Je confirme !


    ::)


     




    La première version est nettement plus lisible...





  • La première version est nettement plus lisible...




    Même avis, je ne suis vraiment pas fan de l'utilisation des variables $0, $1, etc. dans les closures. Ce qu'on économise en nombre de caractères, on le perd en lisibilité :)

  • macphimacphi Membre
    novembre 2017 modifié #17

    Je déterre ce post parce que j'ai bien avancé et je n'ai plus "que" deux warnings qui me donne un peu de fil à  retordre :



    'substring(from:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.

    Voici la ligne fautive, j'ai besoin d'extraire les 4 chiffres derrière le Q (sans mauvais jeu de mots)



    let QNH2 = QNH1.substring( from: QNH1.range(of: "Q", options: .literal, range: nil, locale: nil)?.lowerBound ?? QNH1.startIndex )

    Avez-vous une idée de ce que signifie ce message ?


     


    Et là  vous me direz, t'as demandé à  DuckDuckGo ?


    Oui mais le problème c'est que lorsque j'ai lu les réponses, je ne comprends plus bien la question que j'ai posée...


     


    Et plus généralement connaissez-vous une doc/tuto pour bien gérer les chaines de caractères ?


    Je trouve les fonctions complexes même pour des choses simples...


     


    Merci


  • DrakenDraken Membre
    novembre 2017 modifié #18

    Apple s'amuse à  déprécier des tas de choses en ce moment.


    Quand Xcode signale que quelque chose est deprecated, cela veut dire que cela fonctionne encore, mais que cela n'existera plus dans la version suivante de Swift. C'est pour cela qu'il te recommande d'utiliser ‘partial range from' à  la place.


     


    A part ça, ton code me pique les yeux avec les variables commençant par des MAJUSCULES ! Les majuscules c'est pour les noms de classes..




  • Ton code me pique les yeux avec les variables commençant par des MAJUSCULES !




    Faut pas ?

  • DrakenDraken Membre
    novembre 2017 modifié #20


    Faut pas ?




    NON ..


    La convention de nommage Swift stipule qu'il faut réserver les Majuscules aux noms de classes. Regarde dans la doc Apple, tu ne verras jamais une variable commençant par une majuscule. 


    Cela améliore la lisibilité des programmes.

  • macphimacphi Membre
    novembre 2017 modifié #21

    Ils sont pénibles...


    Le code Q lui est TOUJOURS en majuscule !


    ::)


     


    https://en.wikipedia.org/wiki/Q_code


     


    Encore une histoire de String...


  • Les agences à  3 lettres aussi, mais tu peux les nommer en minuscule



    let cia = " Casse-pieds"
    let fbi = "  Quelqu'un sait-il comment craquer iOS 11 ?"
    let fsb = " Nous tout pareil KBG, mais pas même nom "
  • DrakenDraken Membre
    novembre 2017 modifié #23

    Je ne connais pas la structure de ta chaine de caractères, mais tu peux essayer quelque chose comme :



    let qnh1 = "GjuQ7659"
    if let index = qnh1.range(of: "Q")?.upperBound {
    let chiffres = String(qnh1[index...])
    print (chiffres)
    }


     


    7659



     


    Ce post de SO présente plusieurs manières de remplacer le subscript(from:) déprécié en swift 4 :


     


    https://stackoverflow.com/questions/45562662/how-can-i-use-string-slicing-subscripts-in-swift-4?rq=1




  • Voici la ligne fautive, j'ai besoin d'extraire les 4 chiffres derrière le Q (sans mauvais jeu de mots)




     


    Attention, le QNH peut aussi comporter 3 chiffres seulement...  :-*



  • Attention, le QNH peut aussi comporter 3 chiffres seulement...  :-*




    C'est toujours compliqué les histoires de Q



  •  


    Et plus généralement connaissez-vous une doc/tuto pour bien gérer les chaines de caractères ?


     




    a


    https://developer.apple.com/documentation/swift/string

  • CéroceCéroce Membre, Modérateur
    Dans le principe, Swift est le seul langage qui gère correctement toutes les subtilités d'Unicode. Mais en pratique, il arrive souvent au programmeur de devoir manipuler des chaà®nes ASCII toutes simples, et tout est incroyablement compliqué. Il y aura certainement des évolutions à  ce sujet dans Swift 5.


  •  des chaà®nes ASCII toutes simples, et tout est incroyablement compliqué




     


    Tu me rassures...!


    ::)


     


    Et à  part la doc d'Apple pas toujours facile à  lire, vous n'auriez pas un lien plus "simple" ?


     


    Merci

  • CéroceCéroce Membre, Modérateur
    Il y a bien ça:
    https://useyourloaf.com/blog/swift-string-cheat-sheet/

    Ce n'est pas beaucoup plus simple que la doc d'Apple, mais c'est presque exhaustif, alors que la doc d'Apple ignore de nombreux cas fort courants.
Connectez-vous ou Inscrivez-vous pour répondre.