即使在完成处理程序中,Swift代码也是asynchronous执行的
我很快就有了新的东西,一直在研究如何自己回答这个问题,因为我想学习,但是我完全被难住了。
我有一个从服务器请求数据的函数,并且在接收到数据之后,会执行一个完成处理程序来parsing数据。 在前面提到的完成处理程序中,调用了另一个函数,它本身传递了一个完成处理程序。
由于某种原因,函数中的函数调用正在被跳过,并且在第一个完成处理程序完全执行之后被完成。 下面的代码可能会更有意义:
func loadSites(forceDownload: Bool){ self.inspectionSites = MyData.getLocallyStoredInspectionSites() if self.inspectionSites.count < 1 || forceDownload { self.http.requestSites({(sitesAcquired, jsonObject) -> Void in guard sitesAcquired else{ SwiftOverlays.removeAllBlockingOverlays() MyAlertController.alert("Unable to acquire sites from server or locally") return } let result = jsonObject for (_,subJson):(String, JSON) in result!.dictionaryValue { let site = InspectionSite() site.name = subJson[self.currentIndex]["name"].string! site.city = subJson[self.currentIndex]["city"].string! site.address = subJson[self.currentIndex]["address"].string! site.state = subJson[self.currentIndex]["state"].string! site.zip = subJson[self.currentIndex]["zip"].stringValue site.siteId = subJson[self.currentIndex]["id"].string! objc_sync_enter(self) //SAW A STACKOVERFLOW POST WITH THIS, THOUGHT IT MIGHT HELP MyLocation.geoCodeSite(site, callback:{(coordinates) -> Void in print("YO!!!! GEOCODING SITE!") self.localLat = coordinates["lat"]! self.localLon = coordinates["lon"]! }) objc_sync_exit(self) for type in subJson[self.currentIndex]["inspection_types"]{ let newType = InspectionType() newType.name = type.1["name"].string! newType.id = type.1["id"].string! site.inspectionTypes.append(newType) } site.lat = self.localLat print("HEYY!!!! ASSIGNING COORDS") site.lon = self.localLon let address = "\(site.address), \(site.city), \(site.state) \(site.zip)" site.title = site.name site.subtitle = address MyData.persistInspectionSite(site) self.currentIndex++ } self.inspectionSites = MyData.getLocallyStoredInspectionSites() SwiftOverlays.removeAllBlockingOverlays() self.showSitesOnMap(self.proteanMap) }) }else{ SwiftOverlays.removeAllBlockingOverlays() self.showSitesOnMap(self.proteanMap) } }
我添加了打印“YOOO”和“HEYYY”的打印语句,以便我能够看到正在执行的内容,“HEYY”始终是第一个。 我只需要确保在对象持久化之前总是发生地理编码。 我看到一个提到objc_sync_enter(self)进行同步操作的stackoverflow后,但即时通讯甚至不知道如果这是我所需要的。
这是地理编码网站的function(请帮助):
class func geoCodeSite(site: InspectionSite, callback: ((coordinates: Dictionary<String, String>)->Void)?) { let geocoder = CLGeocoder() let address: String = "\(site.address), \(site.city), \(site.state) \(site.zip)" print(address) geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in if((error) != nil){ print("Error", error) } if let placemark = placemarks?.first { MyLocation.mLat = String(stringInterpolationSegment:placemark.location!.coordinate.latitude) MyLocation.mLon = String(stringInterpolationSegment:placemark.location!.coordinate.longitude) MyLocation.coordinates = ["lat":mLat, "lon":mLon] print(MyLocation.coordinates) callback?(coordinates: MyLocation.coordinates) } }) }
我认为你看到的行为是预期的。 你有两个级别的asynchronous方法:
requestSites geoCodeSite
由于geoCodeSite
方法也是asynchronous的,所以它的callback
在这行之后执行得很好:
MyData.persistInspectionSite(site)
所以你的问题是如何等待,直到所有的 InspectionSite
网站已经geocoded之前坚持的网站,对不对?
调度组可用于检测多个asynchronous事件何时完成,请参阅我的答案。
如何实施派遣小组
dispatch_groups
用于在多个asynchronouscallback完成时触发callback。 在你的情况下,你需要等待所有的geoCodeSite
asynchronouscallback完成之前,坚持你的网站。
因此,创build一个调度组, geoCodeSite
您的geoCodeSite
调用,并实施调度callback,您可以在其中保存您的地理编码网站。
var myGroup = dispatch_group_create() dispatch_group_enter(myGroup) ... fire off your geoCodeSite async callbacks ... dispatch_group_notify(myGroup, dispatch_get_main_queue(), { // all sites are now geocoded, we can now persist site })
不要忘记添加
dispatch_group_leave(myGroup)
里面的geoCodeSiteclosures! 否则,dispatch_group永远不会知道你的asynchronous调用何时完成。