objectWillChange.send() : Erreur cours SwiftUI?

Salut @mbritto

Il semblerait y avoir un erreur dans le cour sur swiftUI, plus précisément l’appel à objectWillChange.send()

objectWillChange.send() n’est pas nécessaire dans la fonction. Le fait de modifier resulList qui est surveillé avec @Published va automatiquement mettre a jour les variables qui dépendent de resulList.

Tu confirmes ?

Et pour de meilleurs perfs, est-ce que ce sera pas mieux de mettre le append et le sort dans uen variavle temporaire puis mettre à à jour resulList à la fin ? ca éviterait de mettre à jour 2 fois resulList et tous les vues et variables qui en dépendent ?

func gameDifiFinish(... {

  let result = GameResult(playerName: username, score: score)
  var newResultList = resultList
  newResultList.append(result)
  newResultList.sort { ... }
  resultList = newResultList

}

Merci.

Je pense que le cours est daté : à l’époque, SwiftUI n’était pas le même qu’aujourd’hui. Je ne suis pas sûr qu’il y ait eu à l’époque un quelconque intérêt à passer par une variable intermédiaire, alors qu’objectWillChange.send était nécessaire pour déclencher la publication. Je pense que le cours était livré à propos du SwiftUI d’iOS13, ça date, et ne prétend pas, j’imagine, représenter la mouture actuelle.
Compte tenu de ce contexte, je ne vois aucune erreur.
J’imagine d’ailleurs que Maxime, qui s’est bien dépensé depuis autour de Directus et de Flutter, va laisser s’éloigner ce cours dans le brouillard du temps…

Vos 2 commentaires font du sens, je suis d’accord avec @djibs sur le fait que @Published et objectWillChange.send() font double emploi et @fjacquemin a raison dans le sens où ces vidéos commencent à dater pas mal.
Je n’ai pas fait de Swift depuis un bon moment, mais de souvenir ça a toujours été le cas donc si c’est vraiment ainsi dans la vidéo alors c’est une erreur.

@djibs Peux-tu me dire dans quelle vidéo c’est exactement que je puisse avoir tout le contexte et éventuellement ajouter une correction à côté de la vidéo ?

C’est vrai qu’aujourd’hui je fais principalement du Flutter et la majorité des apprenants souhaite du Flutter/Dart. Cependant il y a encore une véritable demande pour des cours en Swift et c’est pour ça que nous avons produit plusieurs cours Swift cette année pour Purple Giraffe (tests automatisés, créer une app de A à Z, gagner de l’argent avec vos apps, etc.). Ce cours SwiftUI a bientôt 3 ans et jusqu’à présent je n’ai pas vu de changements majeurs dans SwiftUI nécessitant un nouveau cours.
Après les annonces de la WWDC 2023, ce sera peut être différent :slight_smile:
J’aimerais aussi faire de nouveaux cours qui s’appliqueront à des concepts plus génériques (architecture logicielle, webservices, commercialisation, design, etc.)

@mbritto c’est dans ce cours :

Bonjour,
Si je me souviens bien du cours, Maxime indiquait que c’était pour les propriétés calculées (et un autre quelque chose il me semble, mais je ne me souviens plus) qu’il fallait ce objectWillChange.send().
Et là on a justement la propriété calculée bestGame.
Je pense que c’est pour ça.
Bonne soirée
Pascal

Oui, j’ai eu la curiosité d’aller vérifier, ce n’est pas dans les cours sur iOS 13, c’est dans le cours SwiftUI sur iOS 14. Maxime explique que, pour le résultat retourné par une fonction, ou la valeur d’une propriété calculée, on ne peut pas utiliser @Published. Il n’y a donc aucune erreur dans le cours.

Je suis en train de regarder les nouveautés de la WWDC2023, et il semble bien qu’il y ait des motifs importantes et sympathiques sur ce sujet avec @Observable. Mais je n’ai regardé que par bribes.

@fjacquemin Il y a bien une erreur, j’ai eu confirmation de plusieurs développeurs.

La propriété calculée dépend de la variable resultList qui a le @published, donc quand cette variable est mise à jour toutes les variable qui dépendent d’elle seront aussi mise à jour.

Si la propriété calculée ne dépendait pas de de resultList alors là le objectWillChange.send(). aurait été utile.

De toutes façons, comme le dit Pascal Roques, avec les nouveautés de la WWDC2023, le débat est clos ! Plus aucun souci désormais. Le cours n’est pas erroné, mais il est devenu un peu caduc.

D’ailleurs je n’ai pas pu suivre le meet up de mercredi sur ce sujet, et j’attends avec impatience le replay qui n’a malheureusement pas l’air d’être dispo pour le moment. Quelqu’un l’a suivi? Maxime a parlé de ce point?

Oui, nous avons parle également des macros - une des nouveautés de Swift.

En gros, la class (ne fonctionne pas sur une struct) est prefixée de la macro @Observable qui s’occupe de tout pour nous :

import Observation

@Observable
class GameManager {
     var resultList = [GameResult]()
     var bestGame: GameResult? { resultList.first }
     func gameDidFinish() {}
}

Et on appelle GameViewModel avec le nouveau property wrapper @Bindable :

struct GameView: View {
     @Bindable var viewModel = GameViewModel()
}

La macro transforme le code comme suit :

class GameManager {
    @ObservationTracked var resultList = [GameResult]()
    var bestGame: GameResult? { resultList.first }
    
    func gameDidFinish(username:String, score:Int) {
        let result = GameResult(playerName: username, score: score)
        resultList.append(result)
        resultList.sort { (result1, result2) -> Bool in
            result1.score > result2.score
        }
    }
    
    @ObservationIgnored private let _$observationRegistrar = ObservationRegistrar()
    
    internal nonisolated func access<Member>(
        keyPath: KeyPath<GameManager , Member>
    ) {
        _$observationRegistrar.access(self, keyPath: keyPath)
    }
    
    internal nonisolated func withMutation<Member, T>(
        keyPath: KeyPath<GameManager , Member>,
        _ mutation: () throws -> T
    ) rethrows -> T {
        try _$observationRegistrar.withMutation(of: self, keyPath: keyPath, mutation)
    }
    
    @ObservationIgnored private var _resultList  = [GameResult] ()
}

extension GameManager : Observable  {}

Si tu y a accès, je te conseilles de regarder Platforms State of the Union - WWDC23 - Videos - Apple Developer qui a ete diffuse lundi pares la Keynote.

Cedric

Salu @cedric

Dans des exemples j’ai vu @Bindable n’etait pas toujours employé du coup je ne suis pas sur d’avoir tout compirs.

@Bindable fonctionne un peu comme @State et Binding, sauf que c’est entre la classe et la vue ?

Salut Cedric

Tu as tout a fait raison.

J’ai revu le code de l’app de Maxime et @State serait utilisé dans ce cas.
Il remplace the @StateObject.

On doit utiliser @Bindable quand on modifie une valeur, comme le @Binding d’un TextField - mais comme les valeurs des TextFields de LoginView() sont gerés par le LoginViewModel on sent, @State est a utiliser.

struct GameView: View {
     @State var viewModel = GameViewModel()
}

Cedric