現在のSwiftUI構文に従って@Publishedプロパティラッパーを使用する場合、@ Publishedでプロパティを含むプロトコルを定義するのは非常に難しいようです。
ビューとそのViewModelの間に依存性注入を実装しているので、簡単にプレビューできるようにモックデータを注入できるようにViewModelProtocolを定義する必要があります。
これは私が最初に試したものです
protocol PersonViewModelProtocol {
@Published var person: Person
}
「プロトコル内で宣言されたプロパティ 'person'はラッパーを持つことができません」と表示されます。
それから私はこれを試しました、
protocol PersonViewModelProtocol {
var $person: Published
}
「$」が予約されているため、明らかに機能しませんでした。
ViewとそのViewModelの間にプロトコルを配置し、エレガントな@Published構文を活用する方法を期待しています。どうもありがとう。
これにも遭遇しました。カタリナベータ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
}
}
私は単純な変数を必要とするだけで成功し、フルフィルメントクラスに@Publishedを追加しました。
final class CustomListModel: IsSelectionListModel, ObservableObject {
@Published var list: [IsSelectionListEntry]
init() {
self.list = []
}
...
protocol IsSelectionListModel {
var list: [IsSelectionListEntry] { get }
...
これを試して
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()
}
}
}
}