web-dev-qa-db-ja.com

@Publishedプロパティラッパーでプロパティを含めるプロトコルを定義する方法

現在のSwiftUI構文に従って@Publishedプロパティラッパーを使用する場合、@ Publishedでプロパティを含むプロトコルを定義するのは非常に難しいようです。

ビューとそのViewModelの間に依存性注入を実装しているので、簡単にプレビューできるようにモックデータを注入できるようにViewModelProtocolを定義する必要があります。

これは私が最初に試したものです

protocol PersonViewModelProtocol {
    @Published var person: Person
}

「プロトコル内で宣言されたプロパティ 'person'はラッパーを持つことができません」と表示されます。

それから私はこれを試しました、

protocol PersonViewModelProtocol {
    var $person: Published
}

「$」が予約されているため、明らかに機能しませんでした。

ViewとそのViewModelの間にプロトコルを配置し、エレガントな@Published構文を活用する方法を期待しています。どうもありがとう。

7
UndergroundFox

これにも遭遇しました。カタリナベータ7の時点では、回避策はないようです。そのため、私たちのソリューションは、次のような拡張機能を介して適合性を追加することです。


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 }
}

これは少し余分なセレモニーですが、次のようにすべてのIntBindingContainer実装に機能を追加できます。

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

0
marcprux

私は単純な変数を必要とするだけで成功し、フルフィルメントクラスに@Publishedを追加しました。

final class CustomListModel: IsSelectionListModel, ObservableObject {



    @Published var list: [IsSelectionListEntry]


    init() {

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


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

これを試して

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