web-dev-qa-db-fra.com

Utilisation de environmentObject dans watchOS

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?

18
Paulw11

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()))
    }
}
38
Matteo Pacini

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()))
    }
}
1
mapes911

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
    }
}
0
Zaid Pathan