「OC」AFNetworking的简单使用
前言
在我们进行网络申请的时候,直接使用OC之中自带的NSURL
、NSURLRequest
、NSURLSession
进行相关操作,还需要实现Task
回调、调用resume
。那对我们进行开发来说还是相对比较繁琐的,为了简化我们的网络请求,我们其实可以直接使用AFNetworking这个第三方库进行网络请求的操作(下文简称AFN)。
介绍
我们先来对AFNetworking的核心组件进行介绍
AFHTTPSessionManager:基于 NSURLSession
的管理类,用于发送网络请求和处理响应。AFHTTPSessionManager
是最常用的类,用于处理 HTTP 请求。
AFURLSessionManager:基于 NSURLSession
,用于管理下载、上传等任务。
AFNetworkReachabilityManager:用于监控网络状态的变化。
处理响应格式
AFNetworking 可以自动解析响应的数据格式,常用的解析格式有 JSON、XML、和图片。
-
JSON 响应: 默认情况下,
AFHTTPSessionManager
会将服务器返回的 JSON 自动解析为字典或数组。manager.responseSerializer = [AFJSONResponseSerializer serializer];
-
XML 响应: 如果你的服务器返回 XML,你可以使用
AFXMLParserResponseSerializer
。manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
-
图片下载: AFNetworking 也支持图片下载,并且可以设置下载的图片缓存。
manager.responseSerializer = [AFImageResponseSerializer serializer];
进行简单的GET操作
我们以天气预报的信息申请为例子,如果使用OC之中原生的网络请求,代码大致如下
// 用 NSString 创建 URL
NSString *urlString = @"https://devapi.qweather.com/v7/weather/now?location=101110101&key=487fcdf6fdc9401da0ac4c4df535f43d";
NSURL *url = [NSURL URLWithString:urlString];// 创建 URLSession 对象
NSURLSession *session = [NSURLSession sharedSession];// 创建 URLRequest 对其进行相关请求,这里使用 GET 方法
NSURLRequest *request = [NSURLRequest requestWithURL:url];// 根据会话创建任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {//用block实现回调,处理接受的参数if (error) {NSLog(@"错误: %@", error);return;}NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;if (httpResponse.statusCode >= 200 && httpResponse.statusCode < 300) {NSError *jsonError;NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];if (jsonError) {NSLog(@"解析失败: %@", jsonError);} else {NSLog(@"数据如下: %@", json);// 在这里处理返回的数据}} else {NSLog(@"非法响应: %ld", (long)httpResponse.statusCode);}
}];// 启动任务
[task resume];
如果我们引入AFNetworking库,那么代码就会被简化为以下内容
// 导入 AFNetworking
#import <AFNetworking/AFNetworking.h>// 用 NSString 创建 URL
NSString *urlString = @"https://devapi.qweather.com/v7/weather/now?location=101110101&key=487fcdf6fdc9401da0ac4c4df535f43d";// 使用 AFHTTPSessionManager 来管理请求
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];// 设置响应格式为 JSON
manager.responseSerializer = [AFJSONResponseSerializer serializer];// 发起 GET 请求
[manager GET:urlString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// 请求成功,处理返回数据NSLog(@"数据如下: %@", responseObject);// 在这里处理返回的数据
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// 请求失败,处理错误NSLog(@"错误: %@", error);
}];
我们可以看到,这个程序使用了AFNetworking之中的内容进行操作。其中,GET:parameters:headers:progress:success:failure:
方法是用于发送 GET 请求的基本 API。
responseObject
是返回的数据,AFNetworking 会自动解析 JSON。
添加请求头的GET操作
我们在进行网络请求的时候,有时候会需要用上请求头才能完成完整的网络请求,那我们需要在session的主体之中添加一个请求头。
如果使用OC原生的代码,那么操作还是很繁琐的,拿我们使用Spotify的艺术家申请,代码大致如下
- (void)getArtistInfo:(NSString *)artistID accessToken:(NSString *)accessToken {NSString *urlString = [NSString stringWithFormat:@"https://api.spotify.com/v1/artists/%@",artistID];NSURL *url = [NSURL URLWithString:urlString];NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];[request setHTTPMethod:@"GET"];[request setValue:[NSString stringWithFormat:@"Bearer %@", accessToken] forHTTPHeaderField:@"Authorization"];NSURLSession *session = [NSURLSession sharedSession];NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {if (error) {NSLog(@"%@", error.localizedDescription);return;}NSError *jsonError;NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];if (jsonError) {NSLog(@"%@", jsonError.localizedDescription);return;}Artist *art = [Artist yy_modelWithDictionary:json];NSLog(@"Artist Info:%@",json);NSLog(@"Artist Info: %ld", (long)art.followersTotal);}];[task resume];
}
接下来我们来看看,使用了AFNetworking
- (void)getArtistInfo:(NSString *)artistID accessToken:(NSString *)accessToken {NSString *urlString = [NSString stringWithFormat:@"https://api.spotify.com/v1/artists/%@", artistID];// 创建 AFHTTPSessionManager 实例AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];// 设置请求头[manager.requestSerializer setValue:[NSString stringWithFormat:@"Bearer %@", accessToken] forHTTPHeaderField:@"Authorization"];// 发起 GET 请求[manager GET:urlString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// 成功获取数据NSDictionary *json = (NSDictionary *)responseObject;Artist *art = [Artist yy_modelWithDictionary:json];NSLog(@"Artist Info: %@", json);NSLog(@"Artist Followers Total: %ld", (long)art.followersTotal);} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// 处理错误NSLog(@"%@", error.localizedDescription);}];
}
我们可以看到即使增加了请求头,在AFNetworking之中还是十分的方便的,我们只需要在manager
之中的requestSerializer
使用相关的方法设置它的请求头,再次调用GET
的相关函数。
POST请求
学习完了如何使用AFN完成GET,接下来是网络请求不可或缺的POST请求的学习,下面我使用一个简单的POST函数来实现一个登陆注册的操作
- (void)loginWithUsername:(NSString *)username password:(NSString *)password {NSString *urlString = @"https://api.example.com/login";// 创建 AFHTTPSessionManager 实例AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];// 请求参数NSDictionary *parameters = @{@"username": username, @"password": password};// 发起 POST 请求[manager POST:urlString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// 成功获取响应数据NSLog(@"%@", responseObject);// 在这里可以解析响应数据,比如存储的Token} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// 处理失败NSLog(@"%@", error.localizedDescription);}];
}
可以看到我们实现POST操作和GET操作本质上没有什么特别大的的区别,POST的请求只是讲包装后的字典发送到对应的URL地址,惊醒对应的验证。
使用POST操作上传图片
我们使用POST之中上传图片作为例子,模拟如何进文件的上传
#import <AFNetworking/AFNetworking.h>- (void)uploadImageWithURL:(NSString *)urlStringimageData:(NSData *)imageDataparameters:(NSDictionary *)parameterssuccessBlock:(void (^)(id responseObject))successBlockfailureBlock:(void (^)(NSError *error))failureBlock {// 创建请求管理器AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];// 设置请求的 `Content-Type` 为 `multipart/form-data`[manager POST:urlString parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {// 将二进制图像数据添加到 `formData`[formData appendPartWithFileData:imageDataname:@"file" // 文件字段名,服务器接收的 keyfileName:@"image.jpg" // 文件名,可以随意mimeType:@"image/jpeg"]; // MIME 类型,取决于文件类型} progress:^(NSProgress * _Nonnull uploadProgress) {// 上传进度处理 (可选)NSLog(@"Upload Progress: %.2f%%", 100.0 * uploadProgress.fractionCompleted);} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// 请求成功,处理服务器返回的数据NSLog(@"%@", responseObject);if (successBlock) {successBlock(responseObject);}} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// 请求失败,处理错误NSLog(@"%@", error);if (failureBlock) {failureBlock(error);}}];
}
这里我们使用两个回调的block进行对应的成功和失败的操作,可以确保我们在获取到对应信息之后,再进行接下来的相关操作
NSString *url = @"https://example.com/upload";
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"exampleImage"], 0.9); // 将图片转成NSData格式 即二进制格式
NSDictionary *parameters = @{@"userId": @"12345", @"description": @"Profile Image"};[self uploadImageWithURL:url imageData:imageData parameters:parameters successBlock:^(id responseObject) {NSLog(@"Success response: %@", responseObject);
} failureBlock:^(NSError *error) {NSLog(@"Failed with error: %@", error.localizedDescription);
}];
对于这个方法**appendPartWithFileData:name:fileName:mimeType:
**:
fileData
: 你要上传的文件的二进制数据(如图片的NSData
)。name
: 服务器端接收文件的字段名,通常是"file"
或自定义字段。fileName
: 上传时文件的名字,可以指定任何合适的文件名,比如"image.jpg"
。mimeType
: 上传文件的 MIME 类型,比如"image/jpeg"
、"application/pdf"
。
要是是其他的文件,比如PDF或者MP3格式的,需要调整 fileName
和 mimeType
。例如:
- PDF:
@"application/pdf"
- MP3:
@"audio/mpeg"
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"profile.jpg"], 0.8);
将图片文件转换为 JPEG 格式的二进制数据(NSData
),CGFloat compressionQuality:
这是 JPEG 的压缩质量参数,范围是 0.0
到 1.0
,其中 1.0
表示最高质量,0.0
表示最低质量(高压缩)。通常,0.7
到 0.9
的压缩比可以保持较好的图片质量,同时减少文件大小。
用单例进行网络申请
在进行网络申请的时候,我们可以使用一个AFN实现一个单例类,在项目中使用 AFNetworking 的单例进行网络请求,可以创建一个 AFHTTPSessionManager
的单例类。这有助于网络请求在整个应用中保持统一的配置,比如通用的请求头、超时时间等。这就可以用上我们先前的GCD之中的Once函数。
// NetworkManager.h
#import <AFNetworking/AFNetworking.h>@interface NetworkManager : AFHTTPSessionManager+ (instancetype)sharedManager;@end
.m文件
// NetworkManager.m
#import "NetworkManager.h"@implementation NetworkManager+ (instancetype)sharedManager {static NetworkManager *sharedManager = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// 初始化 AFHTTPSessionManager 并进行一些全局配置sharedManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.yourserver.com/"]];// 例如,设置请求的超时时间sharedManager.requestSerializer.timeoutInterval = 30;// 可以设置请求的序列化格式(默认是JSON)sharedManager.requestSerializer = [AFJSONRequestSerializer serializer];// 可以设置响应的序列化格式(默认是JSON)sharedManager.responseSerializer = [AFJSONResponseSerializer serializer];});return sharedManager;
}@end