La macro @Observable n'existe que depuis iOS 17, sorti en septembre 2023.
Auparavant, le mécanisme d'observation nécessitait trois choses :
Ce mécanisme fonctionne encore mais la macro @Observable est plus simple à utiliser.
Voici un exemple de classe qui définit un objet observable à l'aide de l'ancienne technique.
class Position: ObservableObject {
@Published var x: Double = 0.0
@Published var y: Double = 0.0
@Published var z: Double = 0.0
func modifierPosition() {
... // mécanisme pour modifier une ou plusieurs propriétés publiées
}
}
Et voici un exemple de vue qui doit surveiller un objet de cette classe.
Au même titre qu'une variable d'état, les variables observées forcent le rafraîchissement de la vue dès qu'elles sont modifiées.
struct ContentView: View {
@StateObject private var position: Position = Position() // l'objet est instancié ici
var body: some View {
...
Text(position.x) // sera rafraîchi dès que la propriété change dans la classe
}
}
Prenez note qu'au lieu de @StateObject, il est possible de travailler avec @ObservableObject dans une sous-vue ou encore avec @EnvironmentObject si l'objet a été rendu disponible à tous les descendants.
Si vous devez passer par le constructeur pour initialiser un objet décoré avec @StateObject, quelques précautions s'imposent sinon, vous obtiendrez un message du genre « Cannot assign to property: '...' is a get-only property ».
D'abord, il faut faire précéder le nom de la propriété par une barre de soulignement. En effet, on travaille ici avec une propriété encapsulée, aussi appelée propriété privée sous-jacente (en anglais : backing property) qui a été créée automatiquement lors de la déclaration de la variable décorée avec @StateObject.
Ensuite, il faut utiliser StateObject(wrappedValue:...) pour faire l'initialisation.
Voici un exemple avec une classe qui se charge d'appeler un API dont l'URL est fourni à l'extérieur de la vue.
struct ContentView: View {
@StateObject private var appelAPI: AppelAPI // on ne peut pas instancier l'objet ici puisqu'il nous manque une information
init(chaineURL: String) {
_appelAPI = StateObject(wrappedValue: AppelAPI(chaineURL: chaineURL))
}
« Migrating from the Observable Object protocol to the Observable macro ». Apple. https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro
« Data Flow in SwiftUI ». Tyler Kirtland. https://blog.rocketinsights.com/data-flow-in-swiftui/
« How to use @ObservedObject to manage state from external objects ». Hacking with Swift. https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-observedobject-to-manage-state-from-external-objects
▼Publicité