使用dispatch_async()避免视图阻塞的解决方法是什么

时间:2014-10-27 01:27:25

标签: ios multithreading swift

我有几个标签和一张地图。 在此视图中,我显示了一些有关地理位置点的信息:

  • 地址
  • 地图+图钉
  • 第一个标签(已计算)
  • 第二个标签(已计算)

加载视图后,我需要进行一些计算来更新标签。 这个计算需要几秒钟(我需要调用一个API),所以我把它们放在一个队列中:

dispatch_async(dispatch_get_main_queue(), {
    let loc = CLLocationCoordinate2D(latitude: self.place!.location.latitude, longitude: self.place!.location.longitude)
    let tmp = Int(Geo.apiCall(self.currentPosition, coordTo: loc));
    self.label1.text = " = \(tmp) unit";
})

我使用了主线程dispatch_get_main_queue(),因为我需要更新标签。 问题在于它阻止了地图的渲染,并且还阻止了从地理位置点收集地址的CLGeocoder的其他异步函数。

let loc = CLLocation(latitude: self.place!.location.latitude, longitude: self.place!.location.longitude)

CLGeocoder().reverseGeocodeLocation(loc, completionHandler:
    {(placemarks, error) in
        if error != nil {
            println("reverse geodcode fail: \(error.localizedDescription)")
        }
        let pms = placemarks as [CLPlacemark]
        if pms.count > 0 {
            let pm = placemarks[0] as CLPlacemark
            self.address.text = ABCreateStringWithAddressDictionary(pm.addressDictionary, false)
        }
})

因此视图显示正确,但所有标签在显示视图后几秒钟同时更新,并且仅在呈现标签时才加载地图。

在渲染视图时避免这种阻塞的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT) {
    //Background Thread
    let loc = CLLocationCoordinate2D(latitude: self.place!.location.latitude,         longitude: self.place!.location.longitude)
    let tmp = Int(Geo.apiCall(self.currentPosition, coordTo: loc));

    dispatch_async(dispatch_get_main_queue()) {
        //Run UI Updates
        self.label1.text = " = \(tmp) unit";
    }
}

获取后台线程来完成不直接涉及更改ui的工作,然后在需要时调用主队列。信用到:Understanding dispatch_async

编辑:另一种选择是使用AFNetworking(用于objective-c)Alamofire(用于swift),它将异步调用你的api,你可以在完成处理程序中更改标签:https://github.com/AFNetworking/AFNetworking,tutorial:{ {3}}

EDIT-2:我没有注意并将目标C调用与你的快速声明混合在一起:P

答案 1 :(得分:0)

你应该将计算代码移动到后台队列,在主队列中设置值,这样就可以改变这样的代码:

__block let loc = CLLocationCoordinate2D(latitude: self.place!.location.latitude, longitude: self.place!.location.longitude)
__block let tmp = Int(Geo.apiCall(self.currentPosition, coordTo: loc));
dispatch_async(dispatch_get_main_queue(), {
self.label1.text = " = \(distForYou) unit";

})