Swift NSURLSession:同时运行多个请求时出现问题

时间:2016-04-06 16:01:56

标签: ios swift nsurlsession nsjsonserialization

我正在构建一个天气应用程序,我有一个容器ViewController管理多个子ViewControllers,其主要视图位于容器ViewController的{​​{1}}内。

每个子VC都有一个location属性,它是保存所有天气信息的类。该类具有以下用于从OpenWeatherMaps API加载数据的功能:

UIScrollView

然后子VC有一个函数调用另一个函数,并在主线程上运行completionHandler(因为我正在更新用户界面):

func refresh(completionHandler: () -> ()) {
    let session = NSURLSession.sharedSession()
    session.dataTaskWithURL(self._apiUrl) { (responseData: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
        if let data = responseData {
            do {
                let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
                // parse json
                completionHandler()
            } catch let err as NSError {
                print(err.debugDescription)
            }
        }
    }.resume()
}

最后从ContainerVC我在所有的LocationVC上调用func refreshWeatherData() { location.refresh { dispatch_async(dispatch_get_main_queue(), { print("\(self.location.name)") self.forecastCollectionView.reloadData() }) } } 函数。

refreshWeatherData

现在我遇到的问题是有时(并非总是),一两次或三次,JSONSerialisation会抛出一个错误(在该位置的刷新函数中): override func viewDidLoad() { super.viewDidLoad() let zurich = WALocation(name: "Zürich", id: "7287650", country: "CH", longitude: 8.53071) let shanghai = WALocation(name: "Shanghai", id: "1796236", country: "CN", longitude: 121.45) let boston = WALocation(name: "Boston", id: "4183849", country: "US", longitude: -83.78) let vancouver = WALocation(name: "Vancouver", id: "6173331", country: "CA", longitude: -123.11) addLocationControllerForLocation(shanghai) locationControllers[0].refreshWeatherData() addLocationControllerForLocation(boston) locationControllers[1].refreshWeatherData() addLocationControllerForLocation(zurich) locationControllers[2].refreshWeatherData() addLocationControllerForLocation(vancouver) locationControllers[3].refreshWeatherData() } 而在我的ContainerVC中,我这样做:

Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo ``{NSDebugDescription=No value.}

NSJSONSerialisation永远不会失败。这使我认为只有当多个请求异步运行时它才会失败。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

这听起来像是一个线程问题。您是否尝试在GCD调用中附上刷新调用(或刷新自身)? e.g:

func refresh(completionHandler: () -> ()) {
    dispatch_async(dispatch_get_main_queue()){
        let session = NSURLSession.sharedSession()
        session.dataTaskWithURL(self._apiUrl) { (responseData: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
            if let data = responseData {
                do {
                    let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
                    // parse json
                    completionHandler()
                } catch let err as NSError {
                    print(err.debugDescription)
                }
            }
            }.resume()
    }
}

如果需要,您可以使用dispatch_sync

无论哪种方式,请确保completionHandler回调到正确的线程上的任何内容。如果它是UI更新,那么它就是主线程。

修改的 作为我在下面的帖子的延续,这里是刷新的更新,以在completionHandler中返回数据。

func refresh(completionHandler: (AnyObject) -> ()) {  //Anyobject being your JsonData or whatever so could be NSString, String, etc...
    let session = NSURLSession.sharedSession()
    session.dataTaskWithURL(self._apiUrl) { (responseData: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
        if let data = responseData {
            do {
                let json: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
                // parse json
                completionHandler(json)
            } catch let err as NSError {
                print(err.debugDescription)
            }
        }
    }.resume()
}