iOS开发非完全指南之: 网络请求

现如今单机版本的 APP 几乎不复存在,我们需要掌握如何使用 iOS/web/Android 如何发送 http/https 请求给后端服务,根据响应数据渲染页面。本文主要介绍如何使用 iOS 建立网络请求。

一、网络请求基础使用

1. 网络请求主流程

要实现网络请求需要经历如下几个步骤:

  1. 构造请求的 URL
  2. 创建一个网络请求,网络请求不指定方法默认是 GET
  3. 创建网络管理
  4. 创建一个网络请求任务,并处理响应信息;如有更新 UI 需要回到主线程

  5. 开启网络请求任务任务

一个请求百度首页图片的例子:

- (void) network{

// 1. 创建一个url

NSURL *url= [NSURL URLWithString: @"https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"];

// 2. 创建一个网络请求,网络请求不指定方法默认是GET

NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];

// request.HTTPMethod = @"GET";

// 自定义请求配置

// NSURLSessionConfiguration *config = [[NSURLSessionConfiguration alloc] init];

// config.timeoutIntervalForRequest= 20;// 请求超超时时间

// //...还有很多参数

// NSURLSession *session = [NSURLSession sessionWithConfiguration: config];

// 3. 创建网络管理

NSURLSession *session = [NSURLSession sharedSession];

// 4. 创建一个网络任务

/*

第一个参数 : 请求对象

第二个参数 :

completionHandler回调 ( 请求完成 ["成功"or"失败"] 的回调 )

data : 响应体信息(期望的数据)

response : 响应头信息,主要是对服务器端的描述

error : 错误信息 , 如果请求失败 , 则error有值

*/

NSURLSessionDataTask *task= [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

// data就是服务器返回的数据,response为服务器的响应

if(!error){

// 强转为NSHTTPURLResponse

NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

if(res.statusCode == 200){

// 更新UI必须回到主线程

dispatch_async(dispatch_get_main_queue(), ^{

self.imgView.image = [UIImage imageWithData:data];

});

}

}else{

NSLog(@"报错啦,%@",error);

}

}];

// 5. 开启任务

[task resume];

}

如果你把上面的 https 请求更换成 http,你会发现如下报错:

报错啦,Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x60000246d4d0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png, NSErrorFailingURLKey=http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.

其主要原因是 iOS 默认使用 https 请求,而不是 http;所以会拦截 http 请求,所以会报错。

2. ATS 配置保证访问 Http

要保证 iOS 能够访问 http 请求;需要在 Info.plist 文件中新增如下配置:

<key>NSAppTransportSecurity</key>

<dict>

<key>NSAllowsArbitraryLoads</key>

<true/>

</dict>

3. GET 请求 JSON 并解析

这里使用一个真实的环境,请求 json 数据,返回转换成 Model 并天气列表。主要步骤如下:

  1. 构建一个 url,带中文的 url 进行转换
  2. 创建一个网络请求(url;
  3. 创建网络管理
  4. 创建一个网络任务

    • 网络错误判断
    • 将 JSON 数据 NSData 转换成 NSDictionary(因为服务器返回的是一个{}格式的)
    • 获取数据创建 Model
    • 回到主线程更新数据和 UI

  5. 开启任务

#import "ViewController.h"

#import "Weather.h"

#import "WeatherCell.h"

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, span) NSMutableArray<Weather *> * weathers;

@property (weak, nonatomic) IBOutlet UITableView *weatherTableView;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *indicator;

@end

@implementation ViewController

-(NSMutableArray<Weather *> *)weathers{

if (_weathers == nil) {

// 需要初始化weathers,防止不存在数据,调用weathers.count等报错

_weathers = [NSMutableArray arrayWithCapacity:7];

}

return _weathers;

}

- (void)viewDidLoad {

[super viewDidLoad];

// 设置行高,防止展示高度不足

self.weatherTableView.rowHeight = 100.0;

// 删除Tableview底部的空白区域

self.weatherTableView.tableFooterView = [[UIView alloc]init];

[self weather];

}

-(void)weather{

//1.创建一个url

NSString *net = @"http://v.juhe.cn/weather/index?format=2&cityname=重庆&key=2d2e6e836dbdffac56814bc4d449d507";

//带中文的url进行转换

net = [net stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSURL *url = [NSURL URLWithString:net];

//2.创建一个网络请求(url)

NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];

//request.HTTPMethod = @"POST";

// 自定义请求配置

// NSURLSessionConfiguration *config = [[NSURLSessionConfiguration alloc] init];

// config.timeoutIntervalForRequest= 20;// 请求超超时时间

// //...还有很多参数

// NSURLSession *session = [NSURLSession sessionWithConfiguration: config];

//3.创建网络管理,

NSURLSession *session = [NSURLSession sharedSession];

//4.创建一个网络任务

NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (error) {

NSLog(@"有错误");

}

else {

//需要转换成NSHTTPURLResponse

NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

NSLog(@"%ld", (long)res.statusCode);

/** NSJSONReadingOptions

* NSJSONReadingMutableContainers = (1UL << 0),

* 容器可变,NSMutableDictionary 或NSMutableArray。

*

* NSJSONReadingMutableLeaves = (1UL << 1),

* 叶子可变,返回的 JSON 对象中字符串的值为 NSMutableString。

*

* NSJSONReadingAllowFragments = (1UL << 2)

* 允许 JSON 字符串最外层既不是 NSArray 也不是 NSDictionary,但必须是有效的 JSON 片段

*/

//JSON(字典)转模型

NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];

//取未来7天天气

NSArray *future = dic[@"result"][@"future"];

for(int i = 0; i < future.count; i++){

NSDictionary *wd = future[i];

// 此处创建Weather还有优化空间,详情请见下一节 使用KVC的方式优化json转换Model

Weather *w = [[Weather alloc]init];

w.temperature = wd[@"temperature"];

w.weather = wd[@"weather"];

w.wind = wd[@"wind"];

w.week = wd[@"week"];

w.date_y = wd[@"date"];

[self.weathers addObject:w];

}

NSLog(@"%ld", self.weathers.count);

//默认网络请求在自线程 更新界面要回到主线程

dispatch_async(dispatch_get_main_queue(), ^{

// 模拟加载数据2s,加一点进度条;现实情况是不需要的

[NSThread sleepForTimeInterval:2.0];

//刷新界面

[self.weatherTableView reloadData];

[self.indicator stopAnimating];

});

}

}];

//5.开启任务

[task resume];

}

- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {

WeatherCell *cell = [tableView dequeueReusableCellWithIdentifier:@"weather"];

cell.w = self.weathers[indexPath.row];

return cell;

}

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return self.weathers.count;

}

@end

上面的代码展示了如何请求网络并展示列表,列表如何展示详情请见:iOS 开发-非完全指南之: TableView 的使用详解

4. 使用 KVC 的方式优化 json 转换 Model(优化)

此处的案例是基于上面的 json 请求;前面再获取到 json 数据转换成 NSDictonaray,需要自己手动的创建 Weather 并读取 Key 赋值,在真实的场景下很容易将字段的 key 值写错,所以我们需要使用到 KVC 的方式赋值。

优化前的代码

for(int i = 0; i < future.count; i++){

NSDictionary *wd = future[i];

Weather *w = [[Weather alloc]init];

w.temperature = wd[@"temperature"];

w.weather = wd[@"weather"];

w.wind = wd[@"wind"];

w.week = wd[@"week"];

w.date_y = wd[@"date"];

[self.weathers addObject:w];

}

优化后的代码

for(int i = 0; i < future.count; i++){

NSDictionary *wd = future[i];

Weather *w = [[Weather alloc] initWithDictionary:wd];

[self.weathers addObject:w];

}

需要在 Weath 中构造一个initWithDictionary初始化函数:

//

// Weather.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Weather : NSObject

@property (nonatomic, copy) NSString * temperature;

@property (nonatomic, copy) NSString * weather;

@property (nonatomic, copy) NSString * wind;

@property (nonatomic, copy) NSString * week;

@property (nonatomic, copy) NSString * date_y;

- (instancetype)initWithDictionary:(NSDictionary *) dic; // 新增的

@end

NS_ASSUME_NONNULL_END

然后在 Weather.m 中实现其函数

//

// Weather.m

#import "Weather.h"

@implementation Weather

-(instancetype)initWithDictionary:(NSDictionary *)dic {

if (self = [super init]) {

// 使用KVC的方式给属性赋值,直接将key给Model中的key

[self setValuesForKeysWithDictionary:dic];

}

return self;

}

//属性与字典不匹配时进行改正,不改的话不会崩溃但拿不到值

- (void)setValue:(id)value forKey:(NSString *)key{

//在这里更改key

if([key isEqualToString:@"date"]){

key = @"date_y";

}

[super setValue:value forKey:key];

}

//冗错处理,如果有未定义的字段的话就会走到这里,不重写的话会引起崩溃

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{

NSLog(@"value:%@,undefineKey:%@",value,key);

}

@end

总结:

  • 可以使用setValuesForKeysWithDictionary将字典中的 key 和 value 映射到我们的 Model 中;

  • setValuesForKeysWithDictionary使用前提是返回的 json 和 Model 的属性相同/类似的情况;

  • 在映射的过程中必须处理字段不同setValue,forKey以及不需要的字段 forUndefinedKey

  • 当服务器返回的字段为 iOS 中的关键字也需要使用setValue,forKey进行转换
  • 使用 KVC 的方式能够更好的封装 dic to model 的转换;避免在代码中直接的获取和赋值

5. 发送 POST 请求

发送 POST 网络请求,主要流程和 GET 请求类似,主要差异在构建NSURLRequest的部分;一个简单的例子如下:

//1.创建可变的请求对象

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

//2.修改请求方法为POST

request.HTTPMethod = @"POST";

//4.设置请求体信息,字符串--->NSData

request.HTTPBody = [@"username=mrgaogang&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];

6. 原生文件下载

写在前面: 建议使用 AFNetworking 的文件下载

使用原生的方式实现文件下载主要有如下几个步骤:

  1. 确定需要下载的文件 url
  2. 创建去请求对象
  3. 使用sessionWithConfiguration创建 Session 对象,并设置请求代理NSURLSessionTaskDelegate和队列

    • 实现代理方法监听下载进度: downloadTask bytesWritten totalBytesWritten

    • 实现代理方法实现下载完成存储: downloadTask didFinishDownloadingToURL

  4. 使用downloadTaskWithRequest下载文件
  5. 启动 Task

一个简单的例子:

#import "ViewController.h"

@interface ViewController () <NSURLSessionDownloadDelegate>

@property (weak, nonatomic) IBOutlet UIProgressView *downloadProgress;

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

// 1.确定URL

NSURL *url = [NSURL URLWithString:@"http://localhost:8080/AppTestAPI/wall.png"];

// 2.创建请求对象

NSURLRequest *request = [NSURLRequest requestWithURL:url];

// 3.创建会话对象

//NSURLSession *session = [NSURLSession sharedSession];

// Configuration:配置信息,用默认的即可;将下载的代理方法设置为self并设置为主队列

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];

[downloadTask resume];// 执行Task

}

/**

1.写数据(监听下载进度)

session 会话对象

downloadTask 下载任务

bytesWritten 本次写入的数据大小

totalBytesWritten 下载的数据总大小

totalBytesExpectedToWrite 文件的总大小

*/

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

self.downloadProgress.progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;

}

/**

3.当下载完成的时候调用

location 文件的临时存储路径,在沙盒中的tmp目录下

*/

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{

// 1.拼接文件全路径

// downloadTask.response.suggestedFilename 文件名称

NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];

// 2.剪切文件

[[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];

NSLog(@"%@",fullPath);

}

@end

7. 原生的文件上传

写在前面:建议使用 AFNetworking 的文件上传功能

原生的文件上传功能比较复杂,主要分为如下几个步骤:

    1. 设置上传的 url

    1. 创建请求对象

    • 设置请求头 Content-Type
    • 设置请求方法为 POST , 一般上传走的是 post 请求

    1. 创建请求 Session 代理, NSURLSessionTaskDelegate并实现如下方法

    • 监听上传进度: task didSendBodyData totalBytesSent

    • 监听是否上传完成: task didCompleteWithError

    1. 创建上传 Task: uploadTaskWithRequest

    • 并封装上传数据 fromData 包括启动标记,文件参数和结束标记

    1. 启动 Task

一个简单的例子:

#import "ViewController.h"

@interface ViewController ()<NSURLSessionTaskDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

NSURL *url = [NSURL URLWithString:@"上传的url"];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];

NSString *httpHead = [NSString stringWithFormat:@"multipart/form-data;boundary=----WebKitFormBoundaryUFNaH6losNxu4xDq"];

//设置请求的头 告诉服务器我要上传数据

[request setValue:httpHead forHTTPHeaderField:@"Content-Type"];

request.HTTPMethod = @"POST";

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

//fromData:就是要上传的数据

NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:[self getData] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

NSLog(@"%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);

}];

[task resume];

}

-(NSData *)getData

{

/******************************************************************/

// 设置请求体

// 设置请求体

// 给请求体加入固定格式数据 这里也是使用的也是可变的,因为多嘛

NSMutableData *data = [NSMutableData data];

// 开始标记

// boundary

[data appendData:[@"------WebKitFormBoundaryUFNaH6losNxu4xDq" dataUsingEncoding:NSUTF8StringEncoding]];

// rn换行符

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

// Content-Disposition: form-data; name="myfile"; filename="wall.jpg"

[data appendData:[@"Content-Disposition: form-data; name="myfile"; filename="123.jpg"" dataUsingEncoding:NSUTF8StringEncoding]];

// rn换行符

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

// Content-Type 上传文件的MIME

[data appendData:[@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding]];

// 两个换行符

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

// 上传文件参数

//图片数据 并且转换为Data

UIImage *image = [UIImage imageNamed:@"wall.jpg"];

NSData *imagedata = UIImageJPEGRepresentation(image, 1.0);

[data appendData:imagedata];

//如果是PNG图片需要修改上面几个地方 数据格式如下

// UIImage *image2 = [UIImage imageNamed:@"wall2"];

// NSData *imagedata2 = UIImagePNGRepresentation(image2);

// [data appendData:imagedata2];

//

//如果上传的是zip压缩包

//NSString *path = [[NSBundle mainBundle] pathForResource:@"wall.zip" ofType:nil];

//[data appendData:[NSData dataWithContentsOfFile:path]];

// 两个换行符

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

// 添加结束标记

// rn换行符

[data appendData:[@"------WebKitFormBoundaryUFNaH6losNxu4xDq--" dataUsingEncoding:NSUTF8StringEncoding]];

// boundary

[data appendData:[@"rn" dataUsingEncoding:NSUTF8StringEncoding]];

return data;

}

/*

只要给服务器上传数据就会调用 (一次或多次)

bytesSent: 当前这一次发送的数据长度

totalBytesSent: 总共已经发送的数据长度

totalBytesExpectedToSend: 需要上传的文件的总大小

*/

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend

{

NSLog(@"%lld", 100 * totalBytesSent / totalBytesExpectedToSend);

}

/*

判断是否上传成功,如果失败error是具有值

*/

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error

{

NSLog(@"%s, %@", __func__, error);

}

@end

二、常见第三方库使用

1. AFNetworking 的使用

git 地址: AFNetworking

普通网络请求

AFNetworking 的使用相比原生请求主要有如下差异:

  • 使用了NSURLSessionConfiguration并自定义了 NSURLSession
  • 使用AFURLSessionManager封装了文件上传,下载及断点续传和普通的网络请求
  • 对于普通网络请求直接返回响应后转换的数据 responseObject; 无需自己通过 NSData 转换成 JSON
  • 无需手动回到主线程执行 UI 更新操作

-(void)weather{

//创建管理者

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

//创建网络请求

NSString *net = @"http://v.juhe.cn/weather/index?format=2&cityname=重庆&key=2d2e6e836dbdffac56814bc4d449d507";

net = [net stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSURL *URL = [NSURL URLWithString:net];

NSURLRequest *request = [NSURLRequest requestWithURL:URL];

//创建任务

NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request uploadProgress:^(NSProgress * _Nonnull uploadProgress) {

} downloadProgress:^(NSProgress * _Nonnull downloadProgress) {

} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {

if (error) {

NSLog(@"Error: %@", error);

} else {

//需要转换成NSHTTPURLResponse

NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

NSLog(@"%ld", (long)res.statusCode);

NSLog(@"%@ %@", response, responseObject);

// 网络请求直接返回响应后转换的数据responseObject,无需自己手动转换

//取未来7天天气

NSArray *future = responseObject[@"result"][@"future"];

for(int i = 0; i < future.count; i++){

NSDictionary *wd = future[i];

Weather *w = [[Weather alloc]initWithDictionary:wd];

[self.weathers addObject:w];

}

//刷新界面,无需回到主线程

[self.weatherTableView reloadData];

[self.indicator stopAnimating];

}

}];

//启动任务

[dataTask resume];

}

文件上传

注意点:

  • 主要使用uploadTaskWithRequest完成上传可以使用 process 监听上传进度

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];

NSURLRequest *request = [NSURLRequest requestWithURL:URL];

NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];

NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {

if (error) {

NSLog(@"Error: %@", error);

} else {

NSLog(@"Success: %@ %@", response, responseObject);

}

}];

[uploadTask resume];

文件下载

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL *URL = [NSURL URLWithString:@"https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2529366712,3648628205&fm=26&gp=0.jpg"];

NSURLRequest *request = [NSURLRequest requestWithURL:URL];

NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {

// 此处将文件存储在沙盒中的Document中名称就使用建议的名称,也就是文件默认的名称

NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];

return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];

// 或者使用NSSearchPathForDirectoriesInDomains的方式

// NSString *documentsDirectoryURL = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

// NSString *fileUrl = [documentsDirectoryURL stringByAppendingPathComponent:response.suggestedFilename];

// NSURL *url = [NSURL fileURLWithPath:fileUrl]; // 注意此处必须是fileURLWithPath

// 此处将文件存储在沙盒中的Document中名称就使用建议的名称,也就是文件默认的名称

// return url;

} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {

NSLog(@"File downloaded to: %@", filePath);

}];

[downloadTask resume];

请求参数序列化

请求支持 NSDictionary 不需要再使用?拼接;也支持 POST 请求 HTTPBody

NSString *URLString = @"http://example.com";

NSDictionary *parameters = @{@"foo": @"bar", @"baz": @[@1, @2, @3]};

JSON 类型

[[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];

POST http://example.com/

Content-Type: application/json

{"foo": "bar", "baz": [1,2,3]}

query 参数类型

[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil];

GET http://example.com?foo=bar&baz[]=1&baz[]=2&baz[]=3

表单类型

[[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];

POST http://example.com/

Content-Type: application/x-www-form-urlencoded

foo=bar&baz[]=1&baz[]=2&baz[]=3

检测网络状态(Network Reachability Manager)

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

switch (status) {

case AFNetworkReachabilityStatusNotReachable: //没网络

break;

case AFNetworkReachabilityStatusReachableViaWiFi://WIFI代码

break;

case AFNetworkReachabilityStatusReachableViaWWAN: //蜂窝移动数据

break;

default:

break;

}

}];

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

网络状态 status 有:

  • AFNetworkReachabilityStatusNotReachable : 没网络
  • AFNetworkReachabilityStatusReachableViaWWAN: 蜂窝移动数据
  • AFNetworkReachabilityStatusReachableViaWiFi: WiFi
  • AFNetworkReachabilityStatusUnknown: 未知网络

2. SDWebImage 的使用

SDWebImage 是一个 iOS 端的图片加载库。

git 地址: SDWebImage

基础使用

#import "SDWebImage/UIImageView+WebCache.h"

//通过SDWebImage加载图片

NSURL *url = [NSURL URLWithString:@"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1571140150,993479906&fm=26&gp=0.jpg"];

[self.icon sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"rain"]];

Gift 图片

SDAnimatedImageView *imageView = [SDAnimatedImageView new];

SDAnimatedImage *animatedImage = [SDAnimatedImage imageNamed:@"image.gif"];

imageView.image = animatedImage;

3. 下拉刷新 MJRefresh

git 地址: MJRefresh

MJRefresh 实在是太强大了,不仅仅是下拉刷新,还有上拉加载,指定位置刷新等,建议看官方文档

参考

  • iOS 开发高级-网络编程

以上是 iOS开发非完全指南之: 网络请求 的全部内容, 来源链接: utcz.com/a/31278.html

回到顶部