简体   繁体   中英

IOS, Swift, No way to access main thread in NSURLSession

I am creating an iOS app using swift. I would like to achieve some GET or POST HTTP request. I know that Alamofire exists but i want to create my own functions.

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

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. I would really only use the main thread when touching the UI. Now getting to the matter of performing an HTTP fetch or post I would recommend following the approach that Apple propagates. That is using delegates for handling the asynchronous callbacks. Apple has defined three delegate protocols: NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate. I would create a class, say HTTPClient that implements these protocols:

@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. Of course you need to initialize the dictionary runningTasks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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