Und*_*Fox 16 protocols swiftui combine
在遵循当前 SwiftUI 语法使用 @Published 属性包装器时,似乎很难定义包含带有 @Published 的属性的协议,或者我肯定需要帮助:)
当我在 View 和它的 ViewModel 之间实现依赖注入时,我需要定义一个 ViewModelProtocol 以便注入模拟数据以轻松预览。
这是我第一次尝试的,
protocol PersonViewModelProtocol {
@Published var person: Person
}
Run Code Online (Sandbox Code Playgroud)
我得到“在协议中声明的属性‘人’不能有包装器”。
然后我尝试了这个,
protocol PersonViewModelProtocol {
var $person: Published
}
Run Code Online (Sandbox Code Playgroud)
显然没有用,因为 '$' 是保留的。
我希望有一种方法可以在 View 和它的 ViewModel 之间建立一个协议,并利用优雅的 @Published 语法。非常感谢。
Mur*_*tam 20
我的 MVVM 方法:
// MARK: View
struct ContentView<ViewModel: ContentViewModel>: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Text(viewModel.name)
TextField("", text: $viewModel.name)
.border(Color.black)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewModel: ContentViewModelMock())
}
}
// MARK: View model
protocol ContentViewModel: ObservableObject {
var name: String { get set }
}
final class ContentViewModelImpl: ContentViewModel {
@Published var name = ""
}
final class ContentViewModelMock: ContentViewModel {
var name: String = "Test"
}
Run Code Online (Sandbox Code Playgroud)
怎么运行的:
ViewModel协议继承ObservableObject,因此View将订阅ViewModel更改name有 getter 和 setter,所以我们可以将它用作BindingView更改属性(通过 TextField)时,View 会通过属性name收到更改通知(并且 UI 会更新)@PublishedViewModelView根据您的需要使用真实实现或模拟进行创建可能的缺点:View必须是通用的。
Myc*_*ner 12
您必须明确并描述所有综合属性:
protocol WelcomeViewModel {
var person: Person { get }
var personPublished: Published<Person> { get }
var personPublisher: Published<Person>.Publisher { get }
}
class ViewModel: ObservableObject {
@Published var person: Person = Person()
var personPublished: Published<Person> { _person }
var personPublisher: Published<Person>.Publisher { $person }
}
Run Code Online (Sandbox Code Playgroud)
我认为应该这样做:
public protocol MyProtocol {
var _person: Published<Person> { get set }
}
class MyClass: MyProtocol, ObservableObject {
@Published var person: Person
public init(person: Published<Person>) {
self._person = person
}
}
Run Code Online (Sandbox Code Playgroud)
尽管编译器似乎有点喜欢它(至少是“类型”部分),但类和协议之间的属性访问控制不匹配(https://docs.swift.org/swift-book/LanguageGuide /AccessControl.html)。我尝试了不同的组合:private、public、internal、fileprivate。但没有一个奏效。可能是一个错误?或者缺少功能?
小智 6
我的同事想出的解决方法是使用一个基类来声明属性包装器,然后在协议中继承它。它仍然需要在您的类中继承它也符合协议,但看起来干净并且运行良好。
class MyPublishedProperties {
@Published var publishedProperty = "Hello"
}
protocol MyProtocol: MyPublishedProperties {
func changePublishedPropertyValue(newValue: String)
}
class MyClass: MyPublishedProperties, MyProtocol {
changePublishedPropertyValue(newValue: String) {
publishedProperty = newValue
}
}
Run Code Online (Sandbox Code Playgroud)
然后在实施中:
class MyViewModel {
let myClass = MyClass()
myClass.$publishedProperty.sink { string in
print(string)
}
myClass.changePublishedPropertyValue("World")
}
// prints:
// "Hello"
// "World"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4377 次 |
| 最近记录: |