跳转到主要内容

【iOS】网络请求与异步加载

目录 网络请求 为什么你的图片要异步加载? ​编辑 什么是“异步网络请求” GET 与 POST GET POST 网络请求 1,用NSString创建URL 2,创建NSURL对象:用URLSession对象进行网络请求 3,创建URLRequeset对其进行相关请求,分为GE

原创文章2025iOS 底层iOS网络异步加载【iOS】网络请求与异步加载
作者 TommyWu
本文 1,617 字,阅读预计需要 9 分钟
目录展开
封面图片: 【iOS】网络请求与异步加载

目录

网络请求

为什么你的图片要异步加载?

​编辑

什么是 “异步网络请求”

GET 与 POST

GET

POST

网络请求

1,用 NSString 创建 URL

2,创建 NSURL 对象:用 URLSession 对象进行网络请求

3,创建 URLRequeset 对其进行相关请求,分为 GET 和 POST 方法

4,根据会话创建任务

5,启动任务

图片

在与 web 服务器进行通信的过程中,这些类各自扮演了重要的角色。

NSURL对象负责以 URL 的格式保存 web 应用的位置。对大多数 web 服务,URL 将包含基地址(base address)、web 应用名和需要传送的参数。

NSURLRequest对象负责保存需要传送给 web 服务器的全部数据,这些数据包括:一个NSURL对象、缓存方案(caching policy)、等待 web 服务器响应的最长时间和需要通过 HTTP 协议传送的额外信息(NSMutableURLRequest 是 ** NSURLRequest** 的可变子类)。

每一个NSURLSessionTask对象都表示一个NSURLRequest 的生命周期。NSURLSessionTask可以跟踪 NSURLRequest 的状态,还可以对 NSURLRequest 执行取消、暂停和继续操作。NSURLSessionTask 有多种不同功能 的子类,包括NSURLSessionDataTask,NSURLSessionUploadTask 和 ** NSURLSessionUDownloadTask** 。

NSURLSession对象可以看作是一个生产NSURLSessionTask对象的工厂。可以设置其生产出的NSURLSessionTask对象的通用属性,例如请求头的内容、是否允许在蜂窝网络下发送请求等。NSURLSession 对象还有一个功能强大的委托,可以跟踪 NSURLSessionTask 对象的状态、处理服务器的认证要求等。

-(void) fetchData {
//1、创建URL
NSString *key = @"YOUR_WEATHERAPI_KEY"; // 示例占位符;真实密钥不得硬编码或提交到仓库
NSURLComponents *components = [NSURLComponents componentsWithString:@"https://api.weatherapi.com/v1/forecast.json"];
components.queryItems = @[
[NSURLQueryItem queryItemWithName:@"key" value:key],
[NSURLQueryItem queryItemWithName:@"q" value:self.cityName],
[NSURLQueryItem queryItemWithName:@"days" value:@"7"],
[NSURLQueryItem queryItemWithName:@"lang" value:@"zh"],
[NSURLQueryItem queryItemWithName:@"aqi" value:@"yes"]
];
//2、创建URL对象
NSURL *url = components.URL;
//3、创建URL Request,创建任务
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *weatherDic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
self.weatherData = weatherDic; //最终数据落脚在weatherData
NSLog(@"%@",weatherDic);
dispatch_async(dispatch_get_main_queue(), ^{
/*
分别显示基本天气
每日天气
每小时天气
*/
[self setupWeatherData];
[self setupDailyForecastData];
[self setupHourlyForecastData];
});
}];
//启动任务
[task resume];
}

图片

为什么你的图片要异步加载?

在仿写天气预报时,我们常常需要从网络加载天气图标,例如显示某个小时的天气状态图标。这看似简单的事情,如果处理不当,却很容易造成界面卡顿,甚至影响整个 App 的用户体验。

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
self.weatherIcon.image = [UIImage imageWithData:data];

这段同步读取本身会阻塞调用它的线程;只有从主线程调用时才会阻塞主线程。

  • 若在主线程或 TableView 滚动回调中执行,网络等待会阻塞主线程并导致卡顿。

UIKit 的界面状态更新和事件处理通常应在主线程;具体渲染由系统渲染管线处理。

dataWithContentsOfURL: 是同步 API;编译器通常不会自动提示它可能阻塞主线程。

因此,我们需要异步网络请求。

什么是 “异步网络请求”

URLSession 异步调度网络 I/O,并通过回调或代理交付结果;回调队列由会话配置决定。若需要更新 UI,应显式切回主线程。

1,URLSession + completion handler(块回调)

最常用、简单。适合大多数 GET/POST、加载图片等。

2,URLSession + delegate(代理)

适合需要 “边下边写文件/显示进度/断点续传” 的下载或大文件上传。

3,URLSession + background session

App 退到后台仍能传输(系统托管),适合较大文件上传下载。

异步加载 + 主线程更新 UI

下面是一段优化后的代码:

- (void)loadWeatherIcon:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
self.weatherIcon.image = image;
});
}
}];
[task resume];
}

这段代码我们使用的是第一种:URLSession + completion handler 的 dataTask 异步请求。

解释:

        dataTask : 适合获取内存数据(图片,JSON)

回调方式:completion handler 在请求完成后由会话回调队列执行;具体线程取决于 session/delegate queue 配置,UI 更新应切回主队列。

        配置:sharedSession 

dataTaskWithURL: 会异步执行网络任务,不会等待网络响应后才返回;完成回调运行于会话的回调队列,具体线程不应写成固定线程池。更新 UI 时应显式切回主队列。

  • dispatch_async (dispatch_get_main_queue (), ^{…}) 是我们手动回到主线程更新 UI

使用异步请求后,会显著提升页面响应速度。

至于线程及其他本人暂时还未了解,以后再来填坑。

图片

GET 与 POST

GET

优点:请求资源和查询参数通常由 URL 表示,易于分享、缓存或重放;查询参数不应承载密码、访问令牌等敏感信息。 缺点:参数通常编码在 URL 中,敏感信息可能进入浏览器历史、服务端或代理日志;传输是否加密取决于 HTTPS/TLS,而不是 GET 方法本身。

NSString *urlString = @"https://api.weatherapi.com/v1/current.json?key=xxx&q=beijing";
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@", json);
}
}];
[task resume];
#### POST
POST 常把数据放在请求体中,但请求体不是密文;是否加密取决于是否使用 HTTPS/TLS。它适合按接口约定发送结构化或较大载荷,实际容量仍受各层配置限制。
缺点:需要按接口约定构造请求方法、请求头、请求体和编码;POST 也可由浏览器发送,不能作为保密机制。
HTTP 协议没有统一的“GET最多1024字节、POST无限制”规则;URI、请求头和请求体大小都可能受客户端、服务端、代理或网关限制。
因为post我还没详细了解,给出一段ai代码:
```objective-c
NSURL *url = [NSURL URLWithString:@"https://example.com/api/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 参数放在请求体
NSString *bodyString = @"username=YOUR_USERNAME&password=YOUR_PASSWORD";
request.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
// 设置请求头
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@", json);
}
}];
[task resume];

因为本人的这个天气预报类似于一个小 demo,所以使用 GET,较为简便


原文发布于 CSDN:【iOS】网络请求与异步加载

接着阅读