玩转iOS开发:NSURLSession讲解(二)

文章分享至我的个人技术博客: https://cainluo.github.io/14981091675323.html


继续观看知识

接着上一篇文章继续, 如果没看过的朋友可以去看看玩转iOS开发:NSURLSession讲解(一), 不然的话会不知头不知尾, 那么接来下继续讲.


开始网络请求

之前也说过了, NSURLSession本身是不会进行网络请求的, 那如果我们要用GET或者是POST请求咋搞呢? 直接来看代码吧:

GET请求:

    // 获取共享的单例Session对象
    NSURLSession *urlSession = [NSURLSession sharedSession];
    
    // 请求的URL地址, 我这里拿百度图片的, 而且这里我并没有兼容HTTP, 要兼容HTTP请求的, 可以到工程项目里配置
    NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E5%9B%BE%E7%89%87"];
    
    // 通过上面的URL地址来创建NSURLSessionDataTask对象, 并且在completionHandler:打印一下所获取到的Data数据
    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithURL:url
                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                   
                                                   NSLog(@"请求的数据为: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
                                               }];
    
    // 开始执行任务
    [dataTask resume];
复制代码

POST请求:

    // 获取共享的单例Session对象
    NSURLSession *urlSession = [NSURLSession sharedSession];
    
    // 创建一个NSURL对象
    NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/index?"];
    
    // 创建一个NSMutableURLRequest对象, 并设置HTTPMethod的请求方式和HTTPBody的请求内容.
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
    urlRequest.HTTPMethod = @"POST";
    urlRequest.HTTPBody   = [@"tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E5%9B%BE%E7%89%87" dataUsingEncoding:NSUTF8StringEncoding];
    
    // 通过NSURLRequest对象创建一个NSURLSessionDataTask, 并在completionHandler:回调方法里NSLog一下我们所请求到的数据.
    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:urlRequest
                                                   completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
                                                       NSLog(@"请求的数据为: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
                                                   }];
    
    // 开始执行任务
    [dataTask resume];
复制代码

上传文件

刚刚我们简单的讲了一下GETPOST这两种常用的请求方式, 现在我们来看看上传文件的方法, 上传也有几种方法, 我们一个个来看看:

根据指定的本地文件地址来上传:

    // 创建一个NSURLRequest对象, 注意, 这里要有一个明确的上传地址, 不然你要往哪里上传咧?
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"上传地址"]];
   
    // 本地文件的NSURL
    NSURL *fileURL = [NSURL URLWithString:@"本地文件地址"];
    
    // 通过NSURLRequest对象来创建一个NSURLSessionUploadTask, 配置好File的URL, 还可以在completionHandler: 回调里看看我们是否成功上传.
    NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                    fromFile:fileURL
                                                                           completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                               
                                                                               NSLog(@"上传信息: %@", [NSJSONSerialization JSONObjectWithData:data
                                                                                                                                  options:kNilOptions
                                                                                                                                    error:nil]);
                                               }];
    
    // 开始执行任务
    [uploadTask resume];
复制代码

根据指定的NSData对象来上传:

    // 创建一个NSURLRequest对象
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"上传地址"]];
    
    // 创建一个NSData对象, 这里我就不详细写了, 因为我没有可以上传的服务器
    NSData *fileData = [NSData data];
    
    // 通过NSURLRequest对象来创建一个NSURLSessionUploadTask, 配置好NSData对象, 还可以在completionHandler: 回调里看看我们是否成功上传.
    NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                    fromData:fileData
                                                                           completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                               
                                                                               NSLog(@"上传信息: %@", [NSJSONSerialization JSONObjectWithData:data
                                                                                                                                  options:kNilOptions
                                                                                                                                    error:nil]);
                                                                    }];
                                                                    
    // 执行任务
    [uploadTask resume];
复制代码

以数据流的方式去上传, 老司机们都说这种方式挺不错的, 因为好处就是大小不限制.

    // 初始化一个上传地址
    NSString *urlString = @"上传地址";
    
    // 如果在上传的的URL地址出现特殊字符的话, 我们这里就要做一下特殊处理
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 创建一个NSMutableURLRequest对象
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
    // 网络请求方式设置为POST
    urlRequest.HTTPMethod = @"POST";
    
    // 创建一个NSData对象, 并且设置好上传文件的地址
    NSData *fileData = [NSData dataWithContentsOfFile:@"文件的路径"];
    
    // 通过指定的URLRequest和FildData来创建NSURLSessionUploadTask, 并且可以在completionHandler:方法里获取是否上传成功
    NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                    fromData:fileData
                                                                           completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
                                                                               if (error) {
                                                                                   
                                                                                   NSLog(@"上传发生了错误: %@", error);
                                                                                   
                                                                                   return;
                                                                               }
                                                                               
                                                                               NSLog(@"上传你成功:%@",[[NSString alloc] initWithData:data
                                                                                                                       encoding:NSUTF8StringEncoding]);
                                                                           }];
    
    // 执行任务
    [uploadTask resume];
复制代码

使用表单方式来进行上传, 这里我们需要先自定义两个方法:

// 传入文件的路径, 文件名, 上传的需要更改的文件名
- (NSData *)getHTTPBodyWithFilePath:(NSString *)filePath
                           fileName:(NSString *)fileName
                           restName:(NSString *)restName {
    
    NSMutableData *data = [NSMutableData data];
    
    NSURLResponse *response = [self getLocalFileResponse:filePath];
    
    // 文件类型:MIMEType  文件的大小:expectedContentLength  文件名字:suggestedFilename
    NSString *fileType = response.MIMEType;
    
    // 如果没有传入上传后文件名称,采用本地文件名!
    if (restName == nil) {
        restName = response.suggestedFilename;
    }
    
    // 表单拼接
    NSMutableString *headerString =[NSMutableString string];
    
    [headerString appendFormat:@"--%@\r\n",@"boundary"];
    
    // name:表单控件名称  filename:上传文件名
    [headerString appendFormat:@"Content-Disposition: form-data; name=%@; filename=%@\r\n", fileName, restName];
    [headerString appendFormat:@"Content-Type: %@\r\n\r\n",fileType];
    
    [data appendData:[headerString dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 文件内容
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    
    [data appendData:fileData];
    
    NSMutableString *footerStrM = [NSMutableString stringWithFormat:@"\r\n--%@--\r\n",@"boundary"];
    
    [data appendData:[footerStrM  dataUsingEncoding:NSUTF8StringEncoding]];
    
    NSLog(@"dataStr=%@",[[NSString alloc] initWithData:data
                                              encoding:NSUTF8StringEncoding]);
    
    return data;
}

/// 获取响应,主要是文件类型和文件名
- (NSURLResponse *)getLocalFileResponse:(NSString *)urlString {
    
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    
    // 本地文件请求
    NSURL *url = [NSURL fileURLWithPath:urlString];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    __block NSURLResponse *localResponse = nil;
    
    // 使用信号量实现NSURLSession同步请求
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                         
                                         localResponse = response;
                                         
                                         dispatch_semaphore_signal(semaphore);
                                         
                                     }] resume];
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    return  localResponse;
}
复制代码

现在我们就来开始拼接表单, 并且上传文件:

    // 初始化一个上传地址
    NSString *urlString = @"上传地址";
    
    // 如果在上传的的URL地址出现特殊字符的话, 我们这里就要做一下特殊处理
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
    
    NSURL *url = [NSURL URLWithString:urlString];
    
    // 创建一个NSMutableURLRequest对象
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
    // 网络请求方式设置为POST
    urlRequest.HTTPMethod = @"POST";
    
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", @"boundary"];
    
    [urlRequest setValue:contentType
      forHTTPHeaderField:@"Content-Type"];
    
    // 创建一个NSData对象, 并且设置好上传文件的地址
    NSData *fileData = [self getHTTPBodyWithFilePath:@"/Users/lifengfeng/Desktop/test.jpg"
                                            fileName:@"file"
                                            restName:@"newName.png"];
    
    urlRequest.HTTPBody = fileData;
    
    [urlRequest setValue:[NSString stringWithFormat:@"%lu", fileData.length]
      forHTTPHeaderField:@"Content-Length"];
    
    // 通过指定的URLRequest来创建NSURLSessionUploadTask, 并且可以在completionHandler:方法里获取是否上传成功, 由于我们在URLRequest已经添加了Data数据, 所以这里的FileData可以忽略不理
    NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                    fromData:nil
                                                                           completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
                                                                               if (error) {
                                                                                   
                                                                                   NSLog(@"上传发生了错误: %@", error);
                                                                                   
                                                                                   return;
                                                                               }
                                                                               
                                                                               NSLog(@"上传你成功:%@",[[NSString alloc] initWithData:data
                                                                                                                       encoding:NSUTF8StringEncoding]);
                                                                           }];
    
    // 执行任务
    [uploadTask resume];
复制代码

下载文件

NSURLSessionDownloadTask也是我们常用到的Task, 这里就说说怎么用来下载文件吧:

    // 创建一个文件下载的地址
    NSString *urlString = @"文件下载地址";
    
    // 处理特殊的字符
    urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    
    NSURL *url = [NSURL URLWithString:urlString];
    
    
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    
    NSURLSession *urlSession = [NSURLSession sharedSession];
    
    NSURLSessionDownloadTask *downloadTask = [urlSession downloadTaskWithRequest:urlRequest
                                                               completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                   
                                                                   if(error) {
                                                                       
                                                                       NSLog(@"download error:%@",error);
                                                                       
                                                                       return;
                                                                   }
                                                                   
                                                                   //location:下载任务完成之后,文件存储的位置,这个路径默认是在tmp文件夹下!
                                                                   //只会临时保存,因此需要将其另存
                                                                   
                                                                   NSLog(@"location:%@", location.path);
                                                                   
                                                                   //如果你是用模拟器测试,为了方便可以将保存路径设置为Mac桌面
                                                                   // NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
                                                                   
                                                                   NSString *filePath = @"文件的保存地址";
                                                                   
                                                                   NSError *fileError;
                                                                   
                                                                   [[NSFileManager defaultManager] copyItemAtPath:location.path
                                                                                                           toPath:filePath
                                                                                                            error:&fileError];
                                                                   
                                                                   if(fileError){
                                                                       
                                                                       NSLog(@"file save error: %@",fileError);
                                                                   } else {
                                                                       
                                                                       NSLog(@"file save success");
                                                                   }
                                                               }];

    // 开始下载
    [downloadTask resume];
复制代码

NSURLSessionStreamTask这里就不说了, 因为我也有没有怎么去用


APP的传输安全(ATS)

iOS 9Mac OS 10.11开始, 苹果爸爸就想把所有网络请求都全部改为HTTPS(RFC 2818), 但由于一下子转变肯定是不太可能的, 所以就有一个名为ATS的安全特性.

在新建项目里面, 我们会发没法正常的发送HTTP请求, 这就是ATS搞的鬼, 我们需要在工程里面设置一下, 详细怎么设置去找度娘吧.

如果你想了解更多的资料, 那就去苹果爸爸的官方文档看看Information Property List Key Reference中的NSAppTransportSecurity.


总结

顺便说多一句, 这里的NSURLSessionStreamTask就不讲解了, 用到的机会也不多, 以后有机会再另外开一章节来说说吧.

同样这次依然是没有项目, 大家自己去拷贝代码吧.


最后

码字很费脑, 看官赏点饭钱可好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值