IOS, Swift, 无法访问 NSURLSession 中的主线程
IOS, Swift, No way to access main thread in NSURLSession
我正在使用 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 函数的工作原理相同)。好吧,一切似乎都很好。我实现了使用此 GET 函数 2 次,但是第三次我想使用它时,无法访问主线程来发送数据。我可以在评论 //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)
.
中没有任何记录
有什么想法吗?
我觉得你在这里尝试的东西有点奇怪。您正在从主线程异步分派到主线程。通常你分派异步在另一个线程而不是当前线程上同时执行一些事情,这样当前线程就可以继续做它的事情而不必等待异步任务的完成。当主线程无事可做时,分派到同一个线程(我的猜测)会将任务排队等待稍后执行。我不明白为什么要在主线程上执行这些任务。只要您不尝试操作 UI 对象,任何线程都可以。我真的只会在接触 UI 时使用主线程。
现在开始执行 HTTP 获取或 post 我建议遵循 Apple 传播的方法。那就是使用委托来处理异步回调。 Apple 定义了三个委托协议:NSURLSessionDelegate、NSURLSessionTaskDelegate、NSURLSessionDataDelegate。我会创建一个 class,比如实现这些协议的 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.
我正在使用 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 函数的工作原理相同)。好吧,一切似乎都很好。我实现了使用此 GET 函数 2 次,但是第三次我想使用它时,无法访问主线程来发送数据。我可以在评论 //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)
.
有什么想法吗?
我觉得你在这里尝试的东西有点奇怪。您正在从主线程异步分派到主线程。通常你分派异步在另一个线程而不是当前线程上同时执行一些事情,这样当前线程就可以继续做它的事情而不必等待异步任务的完成。当主线程无事可做时,分派到同一个线程(我的猜测)会将任务排队等待稍后执行。我不明白为什么要在主线程上执行这些任务。只要您不尝试操作 UI 对象,任何线程都可以。我真的只会在接触 UI 时使用主线程。 现在开始执行 HTTP 获取或 post 我建议遵循 Apple 传播的方法。那就是使用委托来处理异步回调。 Apple 定义了三个委托协议:NSURLSessionDelegate、NSURLSessionTaskDelegate、NSURLSessionDataDelegate。我会创建一个 class,比如实现这些协议的 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.