我的数据模型属性是在表视图控制器中声明的,而 SwiftUI 视图是以模态的形式呈现的。我希望呈现的 Form
输入可以操作数据模型。我找到的有关数据流的资源仅适用于 SwiftUI 视图之间,而我在 UIKit 集成方面找到的资源是关于将 UIKit 嵌入 SwiftUI 而不是反过来。
此外,对于值类型(在我的情况下是结构体)的数据模型,是否有一个好的方法?还是将其重新建模为类,使其成为引用类型比较合适?
让我们来分析一下...
我的数据模型属性在表视图控制器中声明,并且SwiftUI视图以模态方式呈现。
那么,这里是您目前拥有的内容(可能被简化了)
struct DataModel {
var value: String
}
class ViewController: UIViewController {
var dataModel: DataModel
// ... some other code
func showForm() {
let formView = FormView()
let controller = UIHostingController(rootView: formView)
self.present(controller, animating: true)
}
}
class ViewController: UIViewController {
var dataModel: DataModel
// ... some other code
func showForm() {
let formView = FormView(data: self.dataModel) { [weak self] newData in
self?.dismiss(animated: true) {
self?.dataModel = newData
}
}
let controller = UIHostingController(rootView: formView)
self.present(controller, animated: true)
}
}
struct FormView: View {
@State private var data: DataModel
private var completion: (DataModel) -> Void
init(data: DataModel, completion: @escaping (DataModel) -> Void) {
self._data = State(initialValue: data)
self.completion = completion
}
var body: some View {
Form {
TextField("", text: $data.value)
Button("Done") {
completion(data)
}
}
}
}
在组织UI代码时,最佳实践要求分为三个部分:
在UIKit中,我们使用MVP方法,其中一个UIViewController子类通常代表秘密酱汁部分。
在SwiftUI中,由于提供了数据绑定工具,更容易使用MVVM方法。在MVVM中,“ViewModel”是秘密酱汁。它是一个自定义结构,保存模型数据供您的视图呈现,当模型数据更新时触发视图更新,并将UI操作转发到模型。
例如,一个编辑名称的表单可以如下所示:
struct MyForm: View {
let viewModel: MyFormViewModel
var body: some View {
Form {
TextField("Name", text: $viewModel.name)
Button("Submit", action: { self.viewModel.submit() })
}
}
}
class MyFormViewModel {
var name: String // implement a custom setter if needed
init(name: String) { this.name = name }
func submit() {
print("submitting: \(name)")
}
}
有了这个,将UI操作转发给UIKit控制器就很容易了。一种标准的方法是使用委托协议:
protocol MyFormViewModelDelegate: class {
func didSubmit(viewModel: MyFormViewModel)
}
class MyFormViewModel {
weak var delegate: MyFormViewModelDelegate?
func submit() {
self.delegate?.didSubmit(viewModel: self)
}
...
最后,你的UIViewController可以实现MyFormViewModelDelegate接口,创建一个MyFormViewModel实例,并通过将self
设置为delegate
进行订阅,然后将MyFormViewModel对象传递给MyForm视图。
改进和其他提示:
didSubmit
事件。$viewModel.name
语法是一个魔法,它创建了一个Binding<String>
实例,该实例引用了MyFormViewModel的可变name
属性。
Binding<...>
,并使用其初始化程序,该初始化程序允许您传递自定义的获取和设置函数,您可以具有消耗实际属性的绑定。 - iltercengiz