NSURLConnection在iOS 9被弃用,NSURLSession是iOS7中新增接口,
NSURLSession,与NSURLConnection是并列的,且可以支持后台相关的网络操作的新特性,NSURLSession把NSURLConnection替换成NSURLSession, NSURLSessionConfiguration,NSURLSessionTask.
基础知识
NSURLSessionTask是一个抽象类,直接使用的三个子类NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask.NSURLSessionDataTask可以执行后面两个子类的功能.
NSURLSessionDataTask-Get方法:
NSURL *url = [NSURL URLWithString:@"http://www.jianshu.com/u/24da48b2ddb3"];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"获取到数据");
}];
// 执行任务/继续执行
[dataTask resume];
//[dataTask suspend];//暂停
NSURLSessionDataTask-Post方法:
NSURL *url = [NSURL URLWithString:@"http://www.jianshu.com/u/24da48b2ddb3"];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *params = @"userName=FlyElephant";//post参数
request.HTTPBody = [params dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"获取到数据");
}];
// 执行任务/继续执行
[dataTask resume];
//[dataTask suspend];//暂停```
NSURLSessionDownloadTask-下载文件:
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
NSURL *url = [NSURL URLWithString:@"http://www.jianshu.com/u/24da48b2ddb3"];
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"GET";
NSURLSessionDownloadTask *dataTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"FlyElephant-下载成功");
}];
// 执行任务/继续执行
[dataTask resume];
第三种方式可以设置delegate,NSURLSessionDelegate定义如下:
@protocol NSURLSessionDelegate <NSObject>
@optional
/* The last message a session receives. A session will only become
* invalid because of a systemic error or when it has been
* explicitly invalidated, in which case the error parameter will be nil.
*/
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error;
/* If implemented, when a connection level authentication challenge
* has occurred, this delegate will be given the opportunity to
* provide authentication credentials to the underlying
* connection. Some types of authentication will apply to more than
* one request on a given connection to a server (SSL Server Trust
* challenges). If this delegate message is not implemented, the
* behavior will be to use the default handling, which may involve user
* interaction.
*/
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
/* If an application has received an
* -application:handleEventsForBackgroundURLSession:completionHandler:
* message, the session delegate will receive this message to indicate
* that all messages previously enqueued for this session have been
* delivered. At this time it is safe to invoke the previously stored
* completion handler, or to begin any internal updates that will
* result in invoking the completion handler.
*/
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session NS_AVAILABLE_IOS(7_0);
@end
有一点需要注意的是如果设置的NSURLSessionDataDelegate,需要在didReceiveResponse方法中加入以下代码:
completionHandler(NSURLSessionResponseAllow);//如果不设置, 将不会执行之后的代理方法
- (void)downloadData {
NSURLSessionConfiguration *configura = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configura delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:@"https://www.jianshu.com/u/24da48b2ddb3"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
[session finishTasksAndInvalidate];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
completionHandler(NSURLSessionResponseAllow);//如果不设置, 将不会执行之后的代理方法
NSLog(@"didReceiveResponse");
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"result: %@", @"didCompleteWithError");
}
文件上传
POST每次都是以NSData的形式上传,如果我们POST传递的既需要传递参数,也需要上传文件,就没上面那么简单了,各位可以先想一下,实现如下:
- (void)originalUploadFile {
NSDictionary *params = @{@"address" : @"简书",
@"userName" : @"FlyElephant"};
NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
NSString *boundary = [self generateBoundaryString];
// 请求的Url
NSURL *url = [NSURL URLWithString:@"http://www.jianshu.com/u/24da48b2ddb3"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
// 设置ContentType
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
NSString *fieldName = @"CustomFile";
NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params paths:@[path] fieldName:fieldName];
NSURLSessionTask *task = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error = %@", error);
return;
}
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"FlyElephant-返回结果---result = %@", result);
}];
[task resume];
}
- (NSData *)createBodyWithBoundary:(NSString *)boundary
parameters:(NSDictionary *)parameters
paths:(NSArray *)paths
fieldName:(NSString *)fieldName {
NSMutableData *httpBody = [NSMutableData data];
// 文本参数
[parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
[httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
}];
// 本地文件的NSData
for (NSString *path in paths) {
NSString *filename = [path lastPathComponent];
NSData *data = [NSData dataWithContentsOfFile:path];
NSString *mimetype = [self mimeTypeForPath:path];
[httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:data];
[httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
[httpBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
return httpBody;
}
- (NSString *)mimeTypeForPath:(NSString *)path {
CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));
CFRelease(UTI);
return mimetype;
}
- (NSString *)generateBoundaryString {
return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
}
实际开发中我们用到的AFNetWorking很容易就实现上面的代码:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"userName": @"FlyElphant"};
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
[manager POST:@"http://www.jianshu.com/u/24da48b2ddb3" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath] name:@"feature" error:nil];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"FlyElephant: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"FlyElephant: %@", error);
}];