【问题标题】:IOS, Swift, No way to access main thread in NSURLSessionIOS,Swift,无法访问 NSURLSession 中的主线程
【发布时间】:2015-02-03 19:17:34
【问题描述】:

我正在使用 swift 创建一个 iOS 应用程序。我想实现一些 GET 或 POST HTTP 请求。我知道 Alamofire 存在,但我想创建自己的函数。

我做了什么:

import Foundation

class DatabaseRequest:NSObject{

    class func GET(urlAsString:String, completion : (response:NSURLResponse, result:AnyObject?, error:String?)-> Void){

        let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
        let session = NSURLSession(configuration: configuration)

        let url = NSURL(string: urlAsString)
        let urlRequest = NSMutableURLRequest(URL: url!)
        urlRequest.HTTPMethod = "GET"

        session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in
            if let error = error{
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    completion(response: response, result: nil, error: "GET Connection error : \(error.localizedDescription)")
                })
            }else{
                var error:NSError?

                let JSON_Object:AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: &error)
                if let error = error{
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        completion(response: response, result: nil, error: "GET JSONSerialization error: \(error.localizedDescription)")
                    })
                }else{
                    if let result:AnyObject = JSON_Object{
                        //The third time I use this class function, no way to access the main thred to send data
                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            completion(response: response, result: JSON_Object, error: nil)
                        })
                    }else{
                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            completion(response: response, result: nil, error: nil)
                        })
                    }
                }
            }

            session.finishTasksAndInvalidate()

        }).resume()

    }

    class func POST(urlAsString:String, parameters:[String:AnyObject], completion:(response:NSURLResponse?, result:AnyObject?, error:String?)->Void){
        println("POST used")
        let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
        let session = NSURLSession(configuration: configuration)

        var errorHTTPBody:NSError?
        let url = NSURL(string: urlAsString)
        let urlRequest = NSMutableURLRequest(URL: url!)
        urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
        urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
        urlRequest.HTTPMethod = "POST"
        urlRequest.HTTPBody = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: &errorHTTPBody)

        if let error = errorHTTPBody{
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completion(response: nil, result: nil, error: "POST errorHTTPBody: \(error.localizedDescription)")
            })
            return
        }

        session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) -> Void in
            println(data)
            if let error = error{
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    completion(response: response, result: nil, error: "POST Connection error : \(error.localizedDescription)")
                })
            }else{
                var error:NSError?
                var JSON_Object:AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: &error)
                if let error = error{
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        completion(response: response, result: nil, error: "POST JSONSerialization error : \(error.localizedDescription)")
                    })
                }else{
                    if let result:AnyObject = JSON_Object{
                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            completion(response: response, result: JSON_Object, error: nil)
                        })
                    }else{
                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            completion(response: response, result: nil, error: nil)
                        })
                    }
                }
            }

            session.finishTasksAndInvalidate()

        }).resume()

    }

}

有趣的部分主要是 GET 函数(因为 POST 函数的工作方式相同)。好吧,一切似乎都很好。我实现了2次使用这个GET函数,但第三次我想使用它,没有办法访问主线程发送数据。我可以在评论 //The third time I use this class function, no way to access the main thread to send data 之前记录一些内容,但 dispatch_async(dispatch_get_main_queue(),block) 中没有任何记录。

有什么想法吗?

【问题讨论】:

    标签: ios swift grand-central-dispatch nsurlsession


    【解决方案1】:

    你在这里尝试的东西对我来说似乎有点奇怪。您正在从主线程异步调度到主线程。通常,您调度 async 以在当前线程之外的另一个线程上同时执行某些操作,因此当前线程可以继续执行其操作而无需等待异步任务完成。当主线程无事可做时,调度到同一个线程(我的猜测)将排队等待稍后执行的任务。我不明白你为什么要在主线程上执行这些任务。只要您不尝试操作 UI 对象,任何线程都可以。我真的只会在触摸 UI 时使用主线程。 现在谈到执行 HTTP 获取或发布的问题,我建议遵循 Apple 传播的方法。那就是使用委托来处理异步回调。 Apple 定义了三个委托协议:NSURLSessionDelegate、NSURLSessionTaskDelegate、NSURLSessionDataDelegate。我会创建一个类,比如实现这些协议的 HTTPClient:

    @interface HTTPClient : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
    
    @property (strong, nonatomic) NSURLSession *session;
    
    @property (strong, nonatomic) NSMutableDictionary *runningTasks;
    
    
    - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data;
    
    - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;
    
    - (NSURLSessionTask *) startGetTaskForURL: (NSURL *) url;
    
    @end
    
    @implementation HTTPClient
    
    - (NSURLSessionTask *) startGetTaskForURL: (NSURL *) url {
        NSURLSessionTask *task = [self.session dataTaskWithURL:url];
        NSMutableData *data = [NSMutableData data];
        [task resume];
        [self.runningTasks setObject:data forKey:task];
        return task;
    }
    
    - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *) dataTask didReceiveData: (NSData *)data {
        NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSMutableData *runningData = [self.runningTasks objectForKey:task];
        if (!runningData) {
            NSLog(@"No data found for task");
        }
        [runningData appendData: data];
    }
    
    - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
        NSData *data = [self.runningTasks objectForKey:task];
        //process the data received
    }
    
    @end
    

    收到所有数据后,您可以执行必要的 JSON 处理。 当然你需要初始化字典 runningTasks。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-30
      • 1970-01-01
      • 2016-06-14
      • 1970-01-01
      • 1970-01-01
      • 2014-08-25
      • 1970-01-01
      相关资源
      最近更新 更多