SwiftUI-如何通过视图模型完成调用函数

问题描述

我有一个获取邮政编码并将其传递给方法的表格。该方法查找城市和州,并将信息作为元组返回。该方法还具有完成处理程序,以便在找到城市和州之前不会保存其余表单数据。

我将函数移至视图模型以使事物井然有序,但现在我感到困惑。首先,必须在函数返回之前调用完成处理程序,即使这似乎与我想要的相反。我想获取城市和州的值,然后然后通过处理程序保存它们。我的困惑的后半部分是函数调用。如果我分配了一个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)
} 

SettingsView

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

解决方法

在完成处理程序中而不是在city中返回statereturn

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
}
,
@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 在模型内部。

在这种情况下,您可以将其用作强制从您的视图中运行代码的东西。

这里的神奇之处在于,如果模型的任何 @Published 变量发生变化,View 将不会完全刷新。这段代码的运行方式与按下位于视图中的按钮内的代码相同!很棒,对吧?)

但如果您不需要这种行为,您可以使用标准的 swiftUI 模型使用方式。我在这里描述过:

https://stackoverflow.com/a/62919526/4423545