SwiftUI - 如何通过视图模型完成调用函数
Posted
技术标签:
【中文标题】SwiftUI - 如何通过视图模型完成调用函数【英文标题】:SwiftUI - How to call function with completion from view model 【发布时间】:2020-09-01 23:45:27 【问题描述】:我有一个获取邮政编码并将其传递给方法的表单。该方法查找城市和州,并将信息作为元组返回。该方法还有一个完成处理程序,以便在找到城市和州之前不会保存其余的表单数据。
我将函数移动到视图模型以保持秩序,但现在我很困惑。首先,必须在函数返回之前调用完成处理程序,即使这看起来与我想要的完全相反。我想获取城市和州的值,然后我想通过处理程序保存它们。我困惑的后半部分是函数的调用。如果我分配一个像cityState
这样的变量来从我的方法接收元组,那么保存会发生在我无法访问的闭包中! (请参阅下面的设置视图代码。)
我可以将所有内容移回正常工作的视图。但我试图了解 MVVM 应该如何工作。
设置视图模型
func getCityStateFromPostalCode(zip: String, completion: @escaping () -> ()) -> (String, String)
let geocoder = CLGeocoder()
var city = ""
var state = ""
geocoder.geocodeAddressString(zip) (placemarks, error) in
if let placemark = placemarks?[0]
if placemark.postalCode == zip
city = placemark.locality!
state = placemark.administrativeArea!
completion()
return (city, state)
设置视图
let settingsVM = SettingsViewModel()
let cityState = settingsVM.getCityStateFromPostalCode(zip: companyZip)
let newCompany = Company(context: self.moc)
newCompany.id = UUID()
newCompany.city = ?? //can't use cityState here.
newCompany.state = ?? // or here!
【问题讨论】:
【参考方案1】:在完成处理程序中返回city
和state
,而不是在return
:
func getCityStateFromPostalCode(zip: String, completion: @escaping ((String, String)) -> ())
let geocoder = CLGeocoder()
var city = ""
var state = ""
geocoder.geocodeAddressString(zip) (placemarks, error) in
if let placemark = placemarks?[0]
if placemark.postalCode == zip
city = placemark.locality!
state = placemark.administrativeArea!
completion((city, state))
那么你可以这样做:
settingsVM.getCityStateFromPostalCode(zip: companyZip) city, state in
let newCompany = Company(context: self.moc)
newCompany.id = UUID()
newCompany.city = city
newCompany.state = state
【讨论】:
【参考方案2】:@ObservedObject var model: someViewModel
var body: some View
ScrollView
ScrollViewReader pageScroller in
ForEach(0..<100) i in
Text("Example \(i)")
.frame(width: 200, height: 200)
.background(colors[i % colors.count])
.id(i)
//Magic here
.onReceive(model.scroller.objectWillChange)
pageScroller.scrollTo(model.scroller.scrollToPageName, anchor: .top)
.frame(height: 350)
class someViewModel: ObservableObject
//Magic here
@ObservedObject var scroller: scrollerHelper
init()
someDelayedCall()
func someDelayedCall()
scroller.scrollToPageName = 8
//Magic here
class scrollerHelper: ObservableObject
@Published var scrollToPageName: Int = -1
scrollerHelper
的主要思想必须作为 ObservedObject 在模型内部。
在这种情况下,您可以使用它来强制代码从您的视图中运行。
这里的神奇之处在于 View 不会像模型的任何 @Published
变量发生变化一样完全刷新。此代码将以与视图中的按钮按下相同的方式运行!太棒了,对吧?)
但如果您不需要这种行为,您可以使用标准的 swiftUI 模型使用方式。我在这里描述过:
https://***.com/a/62919526/4423545
【讨论】:
以上是关于SwiftUI - 如何通过视图模型完成调用函数的主要内容,如果未能解决你的问题,请参考以下文章
如何将我的 SwiftUI 视图的 @State 交换为我的视图模型 @Published 变量?