【AFNetworking】OC 时代网络请求事实标准,Alamofire 的前身
iOS三方库精读 · 第 9 期
一、一句话介绍
AFNetworking 是 iOS / macOS 平台上最早也是最成功的 Objective-C HTTP 网络库,它让网络请求从繁琐的 NSURLConnection / NSURLSession API 变得简洁优雅,成为 OC 时代的事实标准。
| 属性 | 值 |
|---|---|
| GitHub Stars | 33k+ |
| 最新版本 | 4.0.0 |
| License | MIT |
| 支持平台 | iOS 9+ / macOS 10.10+ / watchOS / tvOS |
| 维护状态 | 维护模式(Maintenance Mode) |
二、为什么选择它
原生痛点(2011 年的 iOS 世界)
在没有 AFNetworking 之前,iOS 开发者不得不面对:
- NSURLConnection 样板代码:每次请求都要实现 delegate 回调,代码分散难以维护
- JSON 解析手动处理:iOS 5 之前没有 NSJSONSerialization,需要第三方库
- 图片加载无缓存:网络图片每次都要重新下载,没有内存/磁盘缓存
- 网络状态监听复杂:Reachability API 繁琐,代码量大
- HTTPS 配置困难:自签名证书、SSL Pinning 需要深入了解安全 API
AFNetworking 核心优势
- 一行代码发起请求:GET / POST / PUT / DELETE 统一 API,无需 delegate
- 自动序列化:JSON / XML / Plist / Image 响应自动解析
- UIImageView Category:
setImageWithURL:一行搞定网络图片加载 - Reachability 内建:实时监听网络状态,断网自动提示
- SSL Pinning 支持:证书校验一行配置,安全合规
- Block 回调:告别分散的 delegate,代码逻辑更清晰
原生 API vs AFNetworking
| 场景 | 原生 NSURLSession | AFNetworking |
|---|---|---|
| GET 请求 | 10+ 行代码 + delegate | [manager GET:success:failure:] |
| JSON 解析 | NSJSONSerialization 手动调用 | 自动解析为 NSDictionary / NSArray |
| 图片加载 | 需自行实现缓存 | setImageWithURL: 一行 |
| 网络监听 | Reachability 复杂 API | setReachabilityStatusChangeBlock: |
| 文件上传 | 构造 multipart 请求繁琐 | POST:constructingBodyWithBlock: |
三、核心功能速览
基础层 概念解释、环境配置、基础用法
环境配置
CocoaPods(OC 项目首选)
pod 'AFNetworking', '~> 4.0'
Swift Package Manager
// Package.swift
dependencies: [
.package(url: "https://github.com/AFNetworking/AFNetworking.git", from: "4.0.0")
]
Swift 项目桥接
// {ProjectName}-Bridging-Header.h
#import <AFNetworking/AFNetworking.h>
#import "UIImageView+AFNetworking.h"
基础 GET 请求
// AFNetworking 4.x (OC)
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:@"https://jsonplaceholder.typicode.com/users"
parameters:nil
progress:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"成功: %@", responseObject);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"失败: %@", error.localizedDescription);
}];
进阶层 最佳实践、性能优化、线程安全
POST 请求带参数
NSDictionary *params = @{
@"name": @"张三",
@"email": @"zhangsan@example.com",
@"age": @28
};
[manager POST:@"https://api.example.com/users"
parameters:params
progress:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"创建成功: %@", responseObject);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"创建失败: %@", error);
}];
文件上传
NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
[manager POST:@"https://api.example.com/upload"
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData
name:@"file"
fileName:@"photo.jpg"
mimeType:@"image/jpeg"];
}
progress:^(NSProgress *progress) {
NSLog(@"上传进度: %.0f%%", progress.fractionCompleted * 100);
}
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"上传成功");
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"上传失败: %@", error);
}];
图片加载(UIImageView Category)
#import "UIImageView+AFNetworking.h"
// 基础用法
[imageView setImageWithURL:[NSURL URLWithString:@"https://example.com/avatar.jpg"]];
// 带占位图
[imageView setImageWithURL:[NSURL URLWithString:@"https://example.com/avatar.jpg"]
placeholderImage:[UIImage imageNamed:@"default_avatar"]];
// 取消加载(cell 复用场景)
[imageView cancelImageDownloadTask];
网络状态监听
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:
^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusNotReachable:
NSLog(@"无网络连接");
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"WiFi 连接");
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(@"蜂窝网络");
break;
default:
break;
}
}];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
HTTPS 证书校验
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
manager.securityPolicy.allowInvalidCertificates = YES; // 允许自签名
manager.securityPolicy.validatesDomainName = YES;
深入层 源码解析、设计思想、扩展定制
核心类关系
AFURLSessionManager (核心)
├── AFHTTPSessionManager (HTTP 封装)
│ ├── requestSerializer (请求序列化)
│ └── responseSerializer (响应序列化)
├── AFSecurityPolicy (安全策略)
└── AFNetworkReachabilityManager (网络监听)
Category 扩展:
UIImageView+AFNetworking (图片加载)
UIProgressView+AFNetworking (进度条)
AFNetworkActivityIndicatorManager (状态栏网络指示器)
Session Manager 核心设计
// AFHTTPSessionManager 继承 AFURLSessionManager
// 职责分离:网络层、请求构建、响应解析各自独立
@interface AFHTTPSessionManager : AFURLSessionManager
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> *requestSerializer;
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> *responseSerializer;
@end
// 序列化协议设计
@protocol AFURLRequestSerialization <NSObject>
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError * __autoreleasing *)error;
@end
四、实战演示
场景:完整的网络请求封装
// APIClient.h - 统一网络请求封装
#import <AFNetworking/AFNetworking.h>
@interface APIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
// 业务方法
- (void)fetchUsers:(void(^)(NSArray *users, NSError *error))completion;
- (void)createUser:(NSDictionary *)params
completion:(void(^)(NSDictionary *user, NSError *error))completion;
- (void)uploadAvatar:(UIImage *)image
completion:(void(^)(NSString *url, NSError *error))completion;
@end
// APIClient.m
@implementation APIClient
+ (instancetype)sharedClient {
static APIClient *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURL *baseURL = [NSURL URLWithString:@"https://api.example.com/"];
instance = [[self alloc] initWithBaseURL:baseURL];
// 配置请求/响应序列化
instance.requestSerializer = [AFJSONRequestSerializer serializer];
instance.responseSerializer = [AFJSONResponseSerializer serializer];
instance.requestSerializer.timeoutInterval = 30;
// 添加通用请求头
[instance.requestSerializer setValue:@"application/json"
forHTTPHeaderField:@"Content-Type"];
// HTTPS 配置
instance.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
});
return instance;
}
- (void)fetchUsers:(void(^)(NSArray *users, NSError *error))completion {
[self GET:@"users"
parameters:nil
progress:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
completion(responseObject, nil);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
completion(nil, error);
}];
}
- (void)createUser:(NSDictionary *)params
completion:(void(^)(NSDictionary *user, NSError *error))completion {
[self POST:@"users"
parameters:params
progress:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
completion(responseObject, nil);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
completion(nil, error);
}];
}
- (void)uploadAvatar:(UIImage *)image
completion:(void(^)(NSString *url, NSError *error))completion {
NSData *data = UIImageJPEGRepresentation(image, 0.8);
[self POST:@"upload"
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:data
name:@"avatar"
fileName:@"avatar.jpg"
mimeType:@"image/jpeg"];
}
progress:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
NSString *url = responseObject[@"url"];
completion(url, nil);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
completion(nil, error);
}];
}
@end
五、源码亮点
进阶层 值得借鉴的用法
序列化器组合模式
// 请求序列化器可插拔
manager.requestSerializer = [AFJSONRequestSerializer serializer]; // JSON
manager.requestSerializer = [AFPropertyListRequestSerializer serializer]; // Plist
// 响应序列化器可插拔
manager.responseSerializer = [AFJSONResponseSerializer serializer]; // JSON
manager.responseSerializer = [AFXMLParserResponseSerializer serializer]; // XML
manager.responseSerializer = [AFImageResponseSerializer serializer]; // Image
Block 回调替代 Delegate
// 传统 delegate 分散在多个方法
// AFNetworking 用 block 聚合逻辑
[manager GET:url
parameters:params
progress:^(NSProgress *progress) {
// 进度回调
}
success:^(NSURLSessionDataTask *task, id responseObject) {
// 成功回调
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
// 失败回调
}];
深入层 设计思想解析
NSURLSession 封装架构
// AFURLSessionManager 核心方法
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *, id, NSError *))handler {
// 1. 创建 task
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request];
// 2. 存储 task delegate(用于回调)
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
// 3. 返回 task
return task;
}
// task delegate 处理各种回调
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
// 累积数据,最终一次性回调
[mutableData appendData:data];
}
UIImageView Category 的缓存设计
// UIImageView+AFNetworking 内部使用 AFImageDownloader
// 自动实现内存缓存 + 磁盘缓存
@interface AFImageDownloader : NSObject
@property (nonatomic, strong) AFImageCache *imageCache; // 内存缓存
@property (nonatomic, strong) NSURLCache *urlCache; // 磁盘缓存
@end
// 缓存策略
- (void)downloadImageForURLRequest:(NSURLRequest *)request
completion:(void (^)(UIImage *, NSError *))completion {
// 1. 先查内存缓存
// 2. 再查磁盘缓存
// 3. 最后发起网络请求
}
六、踩坑记录
问题 1:iOS 9+ ATS 限制
问题:iOS 9 默认要求 HTTPS,HTTP 请求被阻止。
原因:App Transport Security (ATS) 默认禁止明文 HTTP。
解决:
<!-- Info.plist 添加例外 -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
问题 2:Response Serializer 编码问题
问题:返回中文乱码或解析失败。
原因:服务器返回非 UTF-8 编码,AFJSONResponseSerializer 默认 UTF-8。
解决:
AFHTTPResponseSerializer *serializer = [AFHTTPResponseSerializer serializer];
serializer.stringEncoding = NSUTF8StringEncoding; // 或其他编码
manager.responseSerializer = serializer;
问题 3:Cell 复用图片错乱
问题:UITableView 快速滚动时,图片显示错误。
原因:Cell 复用时未取消之前的下载任务。
解决:
- (void)prepareForReuse {
[super prepareForReuse];
[self.imageView cancelImageDownloadTask]; // 取消之前的下载
self.imageView.image = nil;
}
问题 4:后台任务未处理
问题:App 进入后台后,下载任务中断。
原因:NSURLSession 默认不支持后台。
解决:
// 使用后台 session configuration
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.background"];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config];
问题 5:Swift 混编桥接头文件缺失
问题:Swift 项目中使用 AFNetworking 报找不到模块。
原因:未配置 Objective-C Bridging Header。
解决:
- 创建
{ProjectName}-Bridging-Header.h文件 - 添加
#import <AFNetworking/AFNetworking.h> - Build Settings → Swift Compiler - General → Objective-C Bridging Header 设置路径
七、延伸思考
AFNetworking vs Alamofire 横向对比
| 维度 | AFNetworking | Alamofire |
|---|---|---|
| 语言 | Objective-C | Swift |
| 首发年份 | 2011 | 2014 |
| GitHub Stars | 33k+ | 41k+ |
| 最低版本 | iOS 9.0 | iOS 12.0 |
| 包体积 | ~500KB | ~300KB |
| 维护状态 | 维护模式 | 活跃开发 |
| Combine 集成 | ❌ 不支持 | ✅ DataRequest.publisher |
| async/await | ❌ 不支持 | ✅ async(...) |
| SwiftUI 支持 | ❌ 不支持 | 需自行封装 |
| 学习曲线 | 中等 | 低(链式 API) |
| OC 兼容性 | 原生 | 需桥接 |
API 对照迁移表
| AFNetworking (OC) | Alamofire (Swift) |
|---|---|
[manager GET:success:failure:] | AF.request(url).response() |
[manager POST:parameters:success:failure:] | AF.request(url, method: .post, parameters: params) |
[manager downloadTaskWithRequest:progress:destination:completion:] | AF.download(url).downloadProgress() |
[manager uploadTaskWithRequest:from:progress:completion:] | AF.upload(multipartFormData:) |
AFNetworkReachabilityManager | NWPathMonitor (系统 API) |
AFSecurityPolicy | ServerTrustManager + PinnedCertificatesTrustEvaluator |
UIImageView+AFNetworking | AlamofireImage / Kingfisher |
选型建议
选 AFNetworking:
- 维护遗留 OC 项目,迁移成本高
- 项目需要支持 iOS 9 ~ iOS 11
- 团队 OC 技术栈成熟,Swift 经验少
选 Alamofire:
- 新项目,Swift 为主要语言
- 需要 Combine / async-await 集成
- 想要更活跃的社区和持续更新
- 最低支持 iOS 12+
渐进式迁移策略
- 共存阶段:OC 模块继续用 AFNetworking,新 Swift 模块用 Alamofire
- 抽象层:统一封装 NetworkService 协议,底层可替换
- 按模块迁移:优先迁移独立的业务模块,而非逐个请求修改
- 测试覆盖:迁移前后确保集成测试通过
八、参考资源
官方资源
相关文章
- AFNetworking 3.0 迁移指南 - Mattt Thompson | 2015
- 从 AFNetworking 到 Alamofire - Ash Furrow | 2015
系列 Demo 仓库
- github.com/ios-lib-dem… - 本系列配套代码
本期互动
小作业
查看你现有的 OC 项目中 AFNetworking 的使用方式,尝试将一个简单的 GET 请求改写为 Alamofire 版本,对比代码量和可读性变化。
思考题
AFNetworking 从 1.x 到 4.x 经历了 NSURLConnection → NSURLSession 的底层迁移,如果你是核心开发者,你会如何设计 API 以保持向后兼容?
读者征集
你在从 AFNetworking 迁移到 Alamofire 的过程中遇到过哪些坑?欢迎评论区分享,优质回答会收录进下一期《踩坑记录》。
📅 本系列每周五晚更新 · 已学习:[✓ Alamofire] [✓ Kingfisher] [✓ Lottie] [✓ MarkdownUI] [✓ SDWebImage] [✓ SnapKit] [✓ ListDiff] [✓ RxSwift] [→ AFNetworking] [○ Charts]