当前位置: 首页 > news >正文

【iOS】AFNetworking学习

【iOS】AFNetworking学习

  • AFNetworking
    • 概念
    • 使用原因
    • 文件构成
  • 单例封装网络请求
  • 认识GET和POST请求
    • GET
    • POST
  • 总结

AFNetworking

概念

AFNetworking是一个基于NSURLSession/NSURLConnection封装的HTTP网络通信框架,可以帮我们更方便地发送请求、接收数据。常用功能有:

  • 发起网络请求
  • 处理返回数据,解析JSON数据
  • 网络状态监听,根据网络状态调整请求策略
  • 支持队列管理,可以同时发送多个请求

使用原因

当我们需要网络请求时,如果不用AFNetworking,代码量很大。以仿写天气预报时的网络请求为例:

//做URL编码
NSString *location = [cityName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
//查城市ID
NSString *cityURLString = [NSString stringWithFormat:@"https://geoapi.qweather.com/v2/city/lookup?location=%@&key=3344bfece6c74eaa911a5f857c30df82", location];
//创建NSURL对象
NSURL *cityURL = [NSURL URLWithString:cityURLString];
//创建请求对象
NSURLRequest *cityRequest = [NSURLRequest requestWithURL:cityURL];
//创建NSURLSession会话
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//协议方法在主线程中执行
//UI更新必须在主线程
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
//根据会话创建请求任务
NSURLSessionDataTask *cityTask = [session dataTaskWithRequest:cityRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (!error) {//解析JSON数据获取城市IDNSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];NSArray *locations = json[@"location"];if (locations.count > 0) {NSString *cityId = locations[0][@"id"];[self requestWeatherWithCityId:cityId cityName:cityName];}}
}];
[cityTask resume];

对比一下通过AFNetworking进行网络请求:

#import "ViewController.h"
#import "AFNetworking.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];NSString *cityName = @"西安";//URL编码NSString *location = [cityName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];//API地址NSString *cityURLString = [NSString stringWithFormat:@"https://geoapi.qweather.com/v2/city/lookup?location=%@&key=3344bfece6c74eaa911a5f857c30df82",location];//创建AFHTTPSessionManagerAFHTTPSessionManager *manager = [AFHTTPSessionManager manager];manager.responseSerializer = [AFJSONResponseSerializer serializer];//GET请求[manager GET:cityURLString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {NSLog(@"返回结果:%@", responseObject);NSDictionary *json = (NSDictionary*)responseObject;NSArray *locations = json[@"location"];if (locations.count > 0) {NSString *cityId = locations[0][@"id"];NSLog(@"城市ID:%@", cityId);}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"请求失败:%@", error.localizedDescription);}];
}@end

编译结果:
在这里插入图片描述

可以看的出,通过AFNetworking实现网络请求代码量会更少。

文件构成

AFNetworking由四部分构成:

  • Manager:管理请求的核心类,封装了网络请求。
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

这里对比一下AFURLSessionManager和AFHTTPSessionManager:

在AFNetworking中,网络请求的manger主要由AFURLSessionManager和AFHTTPSessionManager构成,AFURLSessionManager是AFHTTPSessionManager的父类

父类AFURLSessionManager负责处理一些基础的网络代码,并且接受NSURLRequest对象,而子类AFHTTPSessionManager负责处理和HTTP协议有关的逻辑。

其中,我们使用频率最高的是AFHTTPSessionManager,负责各种HTTP请求的发起和处理,是各种请求的直接执行者。

  • Reachability:网络状态监控,监控网络变化(如WIFI、蜂窝、无网)来调整逻辑。
  • Security:处理网络安全和HTTPS相关的。
  • Serialization:请求和返回数据的序列化器,让AFNetworking自动完成参数封装和JSON数据解析。
manager.responseSerializer = [AFJSONResponseSerializer serializer];

单例封装网络请求

在之前天气预报的仿写中,我们有很多个界面,每个界面中都进行了网络请求,这样非常浪费内存,因此使用单例模式专门负责进行网络请求就会避免这个问题。同时,将网络请求逻辑封装到一个单例类中负责创建、管理和发送网络请求会使得代码集中,提供代码可维护性和可读性。

具体的步骤如下:

  • 创建一个单例类

这里笔者使用了饿汉模式的GCD写法:

+ (instancetype)sharedManager {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{shareManager = [[super allocWithZone:NULL] init];});return shareManager;
}-(instancetype)init {if (self = [super init]) {//管理请求self.sessionManager = [AFHTTPSessionManager manager];//设置请求序列化器,统一请求参数如何编码,方便服务器约定格式self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];//请求超时时间,超过时间触发超时错误self.sessionManager.requestSerializer.timeoutInterval = 15.0;//设置响应序列化器//当服务器返回数据时,响应序列化器负责把它解析成可用Foudation对象。AFJSONResponseSerializer尝试把返回的数据解析成JSON,解析失败把错误抛给failure回调self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];//响应序列化器可以接受的服务器端返回的Content-Type类型有哪些,如果不在集合中,序列化失败,AFNetworking会报错//Content-Type:HTTP响应头里的一个字段,用来告诉客户端,服务器返回的数据是什么类型//@"application/json":返回的是JSON格式//@"text/plain":返回的是纯文本//@"text/html":返回的是HTML网页内容//@"image/png":返回的是一张PNG图片self.sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/plain", @"text/html", nil];}return self;
}
  • 通过AFNetworking中的封装GET方法进行网络请求
//GET封装
//通过封装,只用在NetworkingManager中配置好一次,以后全局通用,并且便于维护
- (void)GET:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers progress:(nullable void (^)(NSProgress * _Nonnull __strong))downloadProgress success:(nullable void (^)(NSURLSessionDataTask * _Nonnull __strong, id  _Nullable __strong))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable __strong, NSError * _Nonnull __strong))failure {//AFNetworking的GET发送请求,把外部传进来的参数传给AFNetworking[self.sessionManager GET:URLString parameters:parameters headers:headers progress:downloadProgress success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {if (success) {success(task, responseObject);}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {if (failure) {failure(task, error);}}];
}

我们具体实现一个实例:

NSString *cityName = @"西安";
NSString *location = [cityName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *urlString = [NSString stringWithFormat: @"https://geoapi.qweather.com/v2/city/lookup?location=%@&key=3344bfece6c74eaa911a5f857c30df82", location];
[[NetworkingManager sharedManager] GET:urlString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"城市:%@", responseObject);NSArray *locations = responseObject[@"location"];NSString *cityId = locations[0][@"id"];NSString *weatherUrl = [NSString stringWithFormat: @"https://geoapi.qweather.com/v2/city/lookup?location=%@&key=3344bfece6c74eaa911a5f857c30df82", cityId];[[NetworkingManager sharedManager] GET:weatherUrl parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"天气:%@", responseObject);} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"天气查询失败:@%@", error);}];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"城市查询失败:%@",error);
}];

这样我们就查询到了天气数据:

在这里插入图片描述

在这里插入图片描述

认识GET和POST请求

GET常用于获取资源,而POST常用于向服务器提供数据,即创建和修改资源。

GET

解释一下上述代码中的有关GET方法请求数据的几个参数:

  • GET:NSString类型,存放URL,即网络请求地址。
  • parameters:NSDictionary类型,存放用于传递请求的数据,在GET请求中这些参数会附加到URL字符串中,以便服务器根据参数返回对应数据。
  • headers:NSDictionary类型,用于设置HTTP请求头的信息,每个请求头都是一个键值对。
  • progress:通常是一个void(^)(NSprogress* downloadProgress)类型的块,它接受一个NSProgress对象(该对象包含已下载的数据量、总数据量等信息),实现更新进度条等操作,用于跟踪下载进度,不需要时传入nil。
  • success:通常是一个void(^)NSURLSessionDataTask* task, id responseObject)类型的块,请求成功后返回该回调块。
    • task:包含响应数据的NSURLSessionDataTask对象
    • responseObject:响应数据,通常是NSDictionary或其他数据结构
  • failure:通常是void(^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)类型的块,请求失败返回该回调块。
    • task:也是包含响应数据的NSURLSessionDataTask对象
    • error:是一个NSError对象,包含请求失败的信息

这里将上面demo的每个参数都不为nil来实现每个参数的作用:

NSString *cityName = @"西安";
NSString *urlString = @"https://geoapi.qweather.com/v2/city/lookup";
NSDictionary *parameters = @{@"location":cityName, @"key": @"3344bfece6c74eaa911a5f857c30df82"};
NSDictionary *headers =  @{@"Content-Type": @"application/json", @"Custom-Header": @"DemoRequest"};
[[NetworkingManager sharedManager] GET:urlString parameters:parameters headers:headers progress:^(NSProgress * _Nonnull downloadProgress) {NSLog(@"下载进度:%.2f", 100.0 * downloadProgress.completedUnitCount);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"请求成功");NSLog(@"请求的Task:%@", task);NSLog(@"响应数据:%@", responseObject);NSArray *locations = responseObject[@"location"];NSString *cityId = locations[0][@"id"];NSLog(@"%@", cityId);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"请求失败");NSLog(@"请求的Task:%@", task);NSLog(@"错误信息:%@", error);
}];

从编译结果中我们就可以看出这几个参数的作用:

在这里插入图片描述

POST

对比一下GET,POST通常会多一个请求体。POST中,参数放在请求体中,服务器通过body解析参数,而GET的参数全部放在URL上,服务器通过URL解析参数。

这里我们针对上面天气预报的查询,需要提交用户反馈,那我们需要实现POST请求:

//请求url
NSString *urlString = @"https://httpbin.org/post";
//请求参数(请求体)
NSDictionary *parameters = @{@"userId":@"1001", @"city":@"西安", @"feedback":@"好用好用"};
//请求头字典,用来告诉服务器请求的额外信息
//"Content-Type": @"application/json":表示请求数据是JSON格式
//@"Custom-Header": @"DemoRequest":自定义的请求头字段,一般用来做标识,告诉服务端这是测试请求
NSDictionary *headers = @{@"Content-Type": @"application/json", @"Custom-Header": @"DemoRequest"};
//创建manager
[[NetworkingManager sharedManager] POST:urlString parameters:parameters headers:headers progress:^(NSProgress * _Nonnull uploadProgress) {NSLog(@"上传进度:%.2f%%", 100.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {NSLog(@"POST请求成功:%@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {NSLog(@"POST请求失败:%@", error.localizedDescription);
}];

实现结果:

在这里插入图片描述

这样我们就成功地用POST请求把JSON数据上传到服务器,并且服务器将确认信息返回给我们。

总结

笔者对AFNetworking仅仅只是进行了学习,具体后面在Spotify中应用会补充在博客中。

http://www.dtcms.com/a/393434.html

相关文章:

  • Kafka 分层存储(Tiered Storage)原理、配置、快速上手与生产落地
  • 多元函数微分学核心概念辨析:连续、偏导与可微
  • 9.21 快选|倍增|栈+贡献法
  • AI.工作助手.工作提效率.AI应用开发平台
  • 【名人简历】鲁迅
  • linux文件系统基本管理
  • 2.1 进程与线程 (答案见原书 P57)
  • SDL2 开发详解
  • c++ 深拷贝之 std::string 与 char*
  • [数理逻辑] 决定性公理与勒贝格可测性(II) 一维情况
  • [Tongyi] DeepResearch Model | MODEL_PATH
  • 儿童对话玩具模型设计与实现
  • 生成器迁移的偏差消除条件
  • LeetCode 刷题【86. 分隔链表】
  • 回溯.专题
  • QML学习笔记(五)QML新手入门其三:使用Row和Colunm进行简单布局
  • 【视图功能11】视图权限控制与协作场景实践
  • YOLOv5至YOLOv12升级:交通标志识别系统的设计与实现(完整代码+界面+数据集项目)
  • 双指针算法案例:有序顺序表的交并差
  • syn和quote实现派生宏Builder
  • MQTT消息质量等级——QoS
  • 【OpenGL】shader 着色器
  • 给AI装上“眼睛”:Schema标记和技术性GEO实战部署
  • 中超-克雷桑破门 齐鲁德比泰山2-2遭海牛读秒绝平!
  • gitflow在公司的全流程
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘grpc’ 问题
  • C语言第17讲
  • 人机协同开发中的“深水炸弹”——指令上下文混淆
  • 朴素贝叶斯算法详解:原理、应用与实践
  • 强化学习的数学原理-02章 贝尔曼公式