简体   繁体   English

iOS,Swift,无法访问NSURLSession中的主线程

[英]IOS, Swift, No way to access main thread in NSURLSession

I am creating an iOS app using swift. 我正在使用Swift创建一个iOS应用。 I would like to achieve some GET or POST HTTP request. 我想实现一些GET或POST HTTP请求。 I know that Alamofire exists but i want to create my own functions. 我知道Alamofire存在,但我想创建自己的函数。

What I have done : 我做了什么 :

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()

    }

}

The interesting part is mostly the GET function (since the POST function works the same). 有趣的部分主要是GET函数(因为POST函数的作用相同)。 Well, everything seems to work fine. 好吧,一切似乎都正常。 I achieve to use this GET function 2 times but the third time I want to use it, there is no way to access the main thread to send data. 我实现了两次使用此GET函数,但是第三次​​使用它,无法访问主线程来发送数据。 I can log something just before my commentary //The third time I use this class function, no way to access the main thread to send data but nothing logs in the dispatch_async(dispatch_get_main_queue(),block) . 我可以在评论之前//The third time I use this class function, no way to access the main thread to send data之前记录一些内容//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)

Any idea? 任何想法?

What you're trying here seems a bit odd to me. 您在这里尝试的操作对我来说有点奇怪。 You're dispatching asynchronously from the main thread to the main thread. 您正在从主线程异步调度到主线程。 Usually you dispatch async to perform something concurrently on another thread than the current one so the current thread can go about doing its thing without having to wait for the completion of the async task. 通常,您分派异步操作以在当前线程以外的另一个线程上并行执行某项操作,因此当前线程可以继续执行其操作,而不必等待异步任务的完成。 Dispatching to the same thread will (my guess) queue the task for execution at a later moment, when the main thread has nothing to do. 当我与主线程无关时,调度到同一线程会使任务排​​队等待稍后执行。 I don't get why you want to have these tasks executed on the main thread. 我不明白为什么要在主线程上执行这些任务。 Any thread would be allright as long as you're not trying to manipulate UI objects. 只要您不尝试操作UI对象,任何线程都可以。 I would really only use the main thread when touching the UI. 我真的只会在触摸UI时使用主线程。 Now getting to the matter of performing an HTTP fetch or post I would recommend following the approach that Apple propagates. 现在开始执行HTTP提取或发布的问题,我建议遵循Apple传播的方法。 That is using delegates for handling the asynchronous callbacks. 那就是使用委托来处理异步回调。 Apple has defined three delegate protocols: NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate. 苹果已经定义了三种委托协议:NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDataDelegate。 I would create a class, say HTTPClient that implements these protocols: 我将创建一个类,例如实现以下协议的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

After receiving all the data you can perform the necessary JSON processing. 收到所有数据后,您可以执行必要的JSON处理。 Of course you need to initialize the dictionary runningTasks. 当然,您需要初始化字典runningTasks。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM