iOS:网络请求再学习

文章目录

网络请求再学习

网络请求的步骤

  1. 创建请求地址

确定接口地址,处理路径和查询参数(如 ?key=xxx&city=beijing)。

  1. 创建请求类

  2. 创建会话

    1. 配置会话

    创建 NSURLSessionConfiguration,设置超时时间、缓存策略、是否允许蜂窝网络等。这一步决定了网络请求的"基调"(默认、临时、后台)。

    1. 创建会话

    利用上一步的配置,生成 NSURLSession 实例。如果不需要代理监听(如进度),直接用 [NSURLSession sharedSession] 即可。

  3. 生成任务

根据业务需求选择任务类型(DataTask / DownloadTask / UploadTask),并传入 URL 或 Request 对象。此时任务处于 suspended(挂起)状态,还未开始联网。

  1. 启动任务

调用 [task resume]

  1. 处理响应数据

如果自定义了 delegate 且会话不再使用,需调用 [session finishTasksAndInvalidate][session invalidateAndCancel] 来打破 sessiondelegate 的强引用。

  1. 清理会话

创建请求地址

在开始学习的时候, 我们创建URL一般是直接使用字符串, 这种方式只适合静态地址 (没有中文, 没有空格, 没有特殊符号)

NSURL *url = [NSURL URLWithString:@"https://api.weatherapi.com/v1/forecast.json"];

创建请求类

NSURLSession 中,苹果提供了一个非常便捷的方法:

objc 复制代码
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;

如果你直接传入 URL,系统会在内部自动帮你创建一个默认的 NSURLRequest (默认使用 GET 方法,默认超时时间,默认缓存策略)。在这种情况下,不需要写 NSURLRequest 的代码,任务就直接生成了

通过这种方式直接生成任务就不用去专门创建请求类了

完整步骤 (显式创建)

如果请求稍微复杂一点(比如 POST 请求、需要加 Headers (如 Token)、需要上传 Body 数据),你就必须 显式地创建 NSMutableURLRequest

objc 复制代码
// 创建请求类
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: url];
    // HTTP 方法
    request.HTTPMethod = @"GET";
    // 时间阈值
    request.timeoutInterval = 15;

创建会话

在iOS中, 创建会话共有3种方式,分别对应不同的业务复杂度

1. 共享单例会话

直接使用系统提供的全局单例对象。

复制代码
NSURLSession *session = [NSURLSession sharedSession];
  • 适用场景:简单的、一次性的 GET/POST 请求,且不需要监听上传/下载进度。
  • 特点 :使用系统默认配置(类似浏览器),无法自定义超时时间、缓存策略 ,且无法设置 Delegate 。所有回调只能通过 completionHandler(闭包)处理。
  • 内存管理:无需管理,它是个单例,App 生命周期内一直存在。

2. 基于配置的会话(无代理,仅闭包回调)

使用 NSURLSessionConfiguration 来创建,但不设置代理 (传入 nil),所有的数据返回都靠 Block 闭包。

复制代码
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.timeoutIntervalForRequest = 30.0;

// 注意:delegate 传 nil,delegateQueue 传 nil 或主队列
NSURLSession *session = [NSURLSession sessionWithConfiguration:config 
                                                      delegate:nil 
                                                 delegateQueue:[NSOperationQueue mainQueue]];
  • 适用场景:需要自定义超时、缓存策略或额外 Headers,但不需要监听进度(如普通的 JSON 接口请求)。
  • 特点 :灵活度高于 sharedSession,但由于没有 Delegate,无法处理需要身份验证(如客户端证书)或重定向的复杂场景。
  • 内存管理 :因为 delegatenil,不存在循环引用问题,会话用完后系统会自动释放,通常不需要手动 invalidate。

NSURLSession* session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]]; 相当于

objc 复制代码
 NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config 
                                                   delegate:nil 
                                              delegateQueue:[NSOperationQueue mainQueue]];

方法的第三个参数 delegateQueue 指的是回调队列

  • 含义 :指定所有代理方法(以及 completionHandler 闭包)在哪个线程执行。
  • 作用 :传入主队列(Main Queue),意味着回调闭包会在主线程执行。

虽然 delegate 传的是 nil,但这个 delegateQueue 依然有效。当使用带 completionHandlerdataTaskWithRequest: 时,这个闭包会在指定的 delegateQueue 上被调用。因为传了 mainQueue,所以成功/失败闭包直接运行在主线程,所以可以安全地在闭包内部更新 UI(如 self.label.text = ...),不需要再手动 dispatch_async(dispatch_get_main_queue())

3. 基于配置 + 自定义代理(全功能模式)

这是最强大、最复杂的模式

复制代码
NSURLSession *session = [NSURLSession sessionWithConfiguration:config 
                                                      delegate:self 
                                                 delegateQueue:[NSOperationQueue mainQueue]];
  • 适用场景 :大文件下载(需要进度条)、大文件上传、需要处理 HTTPS 证书校验(didReceiveChallenge)、需要拦截服务器重定向。
  • 特点 :可以实时接收到 NSURLSessionDelegateNSURLSessionDownloadDelegate 等协议中的回调。
  • 内存管理:会话对象会强引用(retain)代理对象 self 。如果 self 是 ViewController,这就会造成循环引用 ,导致页面 dealloc 不被调用,造成内存泄漏。

生成任务

任务的类型
任务类型 创建方法前缀 核心特征 适用场景
NSURLSessionDataTask dataTaskWith... 数据一次性加载到 内存(NSData) 中返回。 调用 JSON 接口、获取图片二进制数据(小图)。
NSURLSessionUploadTask uploadTaskWith... 专门负责把数据发送给服务器,支持后台上传。 提交头像、上传日志文件、表单提交。
NSURLSessionDownloadTask downloadTaskWith... 数据直接写入磁盘临时文件(NSURL),不占用 App 内存。支持断点续传。 下载视频、更新包、大体积 ZIP 文件。
NSURLSessionStreamTask streamTaskWith... 建立 TCP/IP 流式连接,读写数据按流处理。 即时通讯(IM)、WebSocket 长连接。

笔者目前还处于初始学习过程, 只接触到 NSURLSessionDataTask

任务的回调方式

闭包(Block) 和 代理 (delegate)

回调方式 方法特征 优点 缺点 / 限制
Block 闭包 (Completion Handler) 方法名末尾带 completionHandler: 参数。 代码紧凑 ,发起和处理的逻辑写在一起,易于阅读。 无循环引用风险(若会话无代理,则无需关心内存泄漏)。 无法获取中间进度(DownloadTask 除外,它有单独的进度闭包)。 无法处理服务器要求客户端证书(Authentication Challenge)。 无法拦截重定向。
Delegate 代理 (响应协议方法) 创建会话时传入 delegate:self,并实现 <NSURLSessionDelegate> 等协议。 精细控制 :可以实时监听 didWriteData(进度)、didReceiveChallenge(证书校验)、willPerformHTTPRedirection(重定向)。 分片接收数据 (在 didReceiveData 中手动拼接)。 代码分散 ,逻辑割裂在多个回调方法中。 极易造成循环引用 ,必须手动调用 invalidateAndCancel 断开强引用。
任务的创建方式
输入方式 方法名称特征 能否设置 Method 能否设置 Headers/Body 适用场景
传入 NSURL dataTaskWithURL: downloadTaskWithURL: 固定 GET 不能 简单的 GET 请求,无需携带 Token 或特殊头部。
传入 NSURLRequest dataTaskWithRequest: uploadTaskWithRequest: 自由设置(POST/PUT/DELETE) 能(通过 setValue:forHTTPHeaderField:HTTPBody 需要登录态(Authorization)、需要传 JSON Body 的 POST 请求。
objc 复制代码
    // 创建请求地址
    NSString* str = @"https://your-api.com/login?username=testuser&password=123456";
    NSURL* url = [NSURL URLWithString: str];
    
    // 创建请求类
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: url];
    // HTTP 方法
    request.HTTPMethod = @"GET";
    // 时间阈值
    request.timeoutInterval = 15;
    
    // 配置会话
        // 使用默认配置
    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    // 创建会话
    NSURLSession* session = [NSURLSession sessionWithConfiguration: config];

        // 通过 Request 创建
    NSURLSessionDataTask* task = [session dataTaskWithRequest: request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                if (error) {
            NSLog(@"请求失败: %@", error);
        } else {
            NSError* jsonError = nil;
            // 调用苹果原生 API 将服务器返回的二进制数据 (NSData) 转换为 Objective-C对象
            // 传入错误指针的地址, 如果二进制数据不是合法的 JSON 格式(比如缺了一个引号,或者是 HTML 报错页),jsonError 就会被赋值为一个包含具体错误原因的对象,而方法本身会返回 nil。
            id dict = [NSJSONSerialization JSONObjectWithData: data options:0 error: &jsonError];
            if (jsonError) {
                NSLog(@"JSON 解析失败");
            } else {
                NSLog(@"%@", dict);
            }
        }
    }];
//启动任务
[dataTask resume];

这是通过 requset 和 闭包 (Block) 回调的方式创建task, 还可以采用一个 [session dataTaskWithURL:url completionHandler:]的方式去创建一个,但是如果以后面的方式去创建的话,就意味着是以一种GET方式去获取网络请求,这样只能满足一些简单的网络请求,而使用 request 方式来获取数据可以满足更复杂的情况。

所以我们尽量采用request方法来获取网络请求,采用request的方式可以满足更多需求

下面是通过 URL 创建任务

objc 复制代码
// 创建地址
NSURL *url = [NSURL URLWithString:@"https://api.example.com/public/data"];

// 配置会话
        // 使用默认配置
    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    // 创建会话
    NSURLSession* session = [NSURLSession sessionWithConfiguration: config
                                                          delegate: nil
                                                     delegateQueue: [NSOperationQueue mainQueue]];

// 创建任务(直接传入 URL)
NSURLSessionDataTask *task = [session dataTaskWithURL:url 
                                    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error) {
        NSLog(@"请求失败: %@", error);
    } else {
        NSError* jsonError = nil;
        // 调用苹果原生 API 将服务器返回的二进制数据 (NSData) 转换为 Objective-C对象
        // 传入错误指针的地址, 如果二进制数据不是合法的 JSON 格式(比如缺了一个引号,或者是 HTML 报错页),jsonError 就会被赋值为一个包含具体错误原因的对象,而方法本身会返回 nil。
        id dict = [NSJSONSerialization JSONObjectWithData: data options:0 error: &jsonError];
        if (jsonError) {
            NSLog(@"JSON 解析失败");
        } else {
            NSLog(@"%@", dict);
        }
    }
}];

//  启动任务
[task resume];

通过URL创建任务就不用显式的去创建请求类

启动任务

启动任务的唯一正确方法: [task resume]

刚刚创建好的任务, 处于 suspended (挂起) 的状态 , 它虽然存在, 但是不会发出任何网络请求

相关推荐
世人万千丶1 小时前
鸿蒙Crash高级捕获与异常监控:全局异常兜底/崩溃栈解析/符号表还原/智能聚类/闭环修复
学习·机器学习·华为·数据挖掘·harmonyos·鸿蒙·聚类
一名普通的电源工程师2 小时前
E0512XT-1WR3 适配优选 钡特电源 DF1-05D12XT|1W 隔离5V转±12V模块电源选型参数技术解析
大数据·网络·人工智能
Jul1en_2 小时前
【Claude Code Compact】源码级别的学习上下文压缩
java·前端·学习·github·ai编程
fengci.2 小时前
Microweber CMS 未授权路径穿越漏洞(CVE-2026-65694)
android·开发语言·前端·学习·php
2301_780789662 小时前
零信任时代:WAF 从边界防护到微隔离的架构跃迁
网络·安全·web安全·kubernetes·ddos
m4Rk_3 小时前
【论文阅读】Agent 记忆机制(28):MEM1——将记忆压缩融入推理,实现近似恒定上下文的长程智能体
论文阅读·人工智能·学习·开源·github
一只小菜鸡..3 小时前
南京大学 操作系统 (JYY) 学习笔记:持久化的黑魔法——从磁铁、刻坑到闪存电荷
服务器·笔记·学习
牛马工作号3 小时前
蓝牙技术全景指南:从无线链路、协议栈到产品量产
网络
中电华星3 小时前
专业的工业电源公司
网络·python