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.lxweimin.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.lxweimin.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.lxweimin.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:@"http://www.lxweimin.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.lxweimin.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.lxweimin.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);
}];