J'essaie d'utiliser environmentObject
dans une application watchOS6 pour lier mon modèle de données à ma vue.
J'ai créé une application Watch simple et autonome dans Xcode 11.
J'ai créé une nouvelle classe DataModel
import Combine
import Foundation
import SwiftUI
final class DataModel: BindableObject {
let didChange = PassthroughSubject<DataModel,Never>()
var aString: String = "" {
didSet {
didChange.send(self)
}
}
}
Dans ma structure ContentView
, je lie cette classe à l'aide de @EnvironmentObject
-
struct ContentView : View {
@EnvironmentObject private var dataModel: DataModel
var body: some View {
Text($dataModel.aString.value)
}
}
Enfin, j'essaie d'injecter une instance de DataModel
dans l'environnement dans la classe HostingController
-
class HostingController : WKHostingController<ContentView> {
override var body: ContentView {
return ContentView().environmentObject(DataModel())
}
}
Mais, j'obtiens une erreur:
Cannot convert return expression of type '_ModifiedContent<ContentView, _EnvironmentKeyWritingModifier<DataModel?>>' to return type 'ContentView'
L'erreur est due au fait que WKHostingController
est un générique qui a besoin d'un type concret - WKHostingController<ContentView>
dans ce cas.
Une approche similaire fonctionne parfaitement avec UIHostingController
dans une application iOS car UIHostingController
n'est pas une classe générique.
Existe-t-il un autre moyen d'injecter l'environnement dans une vue watchOS?
Vous pouvez utiliser l'effacement de type, AnyView
dans le cas de SwiftUI View
.
Je voudrais refactoriser WKHostingController
pour retourner AnyView
.
Cela semble bien se compiler de mon côté.
class HostingController : WKHostingController<AnyView> {
override var body: AnyView {
return AnyView(ContentView().environmentObject(DataModel()))
}
}
Pour quelqu'un comme Brett (dans les commentaires) qui recevait
"Property 'body' with type 'AnyView' cannot override a property with type 'ContentView'"
J'ai eu la même erreur car je n'avais pas remplacé la valeur de retour et encapsulé le ContentView renvoyé.
c'est à dire. voici à quoi ressemblait ma première tentative .. remarquez le WKHostingController<ContentView>
ça devrait être WKHostingController<AnyView>
class HostingController : WKHostingController<ContentView> {
override var body: AnyView {
return AnyView(ContentView().environmentObject(DataModel()))
}
}
Ajoutant à la réponse impressionnante de Matteo,
Si vous souhaitez utiliser délégué, utilisez comme ceci:
class HostingController : WKHostingController<AnyView> {
override var body: AnyView {
var contentView = ContentView()
contentView.environmentObject(DataModel())
contentView.delegate = self
let contentWrapperView = AnyView(contentView)
return contentWrapperView
}
}