web-dev-qa-db-fra.com

Comment définir un protocole pour inclure une propriété avec le wrapper de propriété @Published

Lorsque vous utilisez le wrapper de propriété @Published selon la syntaxe SwiftUI actuelle, il semble très difficile de définir un protocole qui inclut une propriété avec @Published, ou j'ai vraiment besoin d'aide :)

Comme j'implémente l'injection de dépendances entre une vue et son ViewModel, je dois définir un ViewModelProtocol afin d'injecter des données fictives pour prévisualiser facilement.

C'est ce que j'ai essayé pour la première fois,

protocol PersonViewModelProtocol {
    @Published var person: Person
}

J'obtiens "La propriété 'personne' déclarée dans un protocole ne peut pas avoir de wrapper".

Alors j'ai essayé ça,

protocol PersonViewModelProtocol {
    var $person: Published
}

Évidemment, cela n'a pas fonctionné car '$' est réservé.

J'espère un moyen de mettre un protocole entre View et son ViewModel et en tirant également parti de l'élégante syntaxe @Published. Merci beaucoup.

7
UndergroundFox

Nous l'avons également rencontré. À partir de Catalina beta7, il ne semble pas y avoir de solution de contournement, donc notre solution est d'ajouter une conformité via une extension comme ceci:


struct IntView : View {
    @Binding var intValue: Int

    var body: some View {
        Stepper("My Int!", value: $intValue)
    }
}

protocol IntBindingContainer {
    var intValue$: Binding<Int> { get }
}

extension IntView : IntBindingContainer {
    var intValue$: Binding<Int> { $intValue }
}

Bien que ce soit un peu plus de cérémonie, nous pouvons ensuite ajouter des fonctionnalités à toutes les implémentations IntBindingContainer comme ceci:

extension IntBindingContainer {
    /// Reset the contained integer to zero
    func resetToZero() {
        intValue$.wrappedValue = 0
    }
}

0
marcprux

J'ai réussi à simplement exiger la variable simple, et en ajoutant le @Published dans la classe épanouissante:

final class CustomListModel: IsSelectionListModel, ObservableObject {



    @Published var list: [IsSelectionListEntry]


    init() {

        self.list = []
    }
...
protocol IsSelectionListModel {


    var list: [IsSelectionListEntry] { get }
...
0
Hardy

Essaye ça

import Combine
import SwiftUI

// MARK: - View Model

final class MyViewModel: ObservableObject {

    @Published private(set) var value: Int = 0

    func increment() {
        value += 1
    }
}

extension MyViewModel: MyViewViewModel { }

// MARK: - View

protocol MyViewViewModel: ObservableObject {

    var value: Int { get }

    func increment()
}

struct MyView<ViewModel: MyViewViewModel>: View {

    @ObservedObject var viewModel: ViewModel

    var body: some View {

        VStack {
            Text("\(viewModel.value)")

            Button("Increment") {
                self.viewModel.increment()
            }
        }
    }
}
0
Emil Landron