MST

星途 面试题库

面试题:Objective-C中AFNetworking源码深度剖析与优化

深入分析AFNetworking在处理复杂网络场景(如网络切换、请求超时重连、数据缓存等)时的实现原理,并结合实际项目经验,阐述你认为AFNetworking在这些方面存在哪些可优化的点,如果你要对其进行优化,你会从哪些方面入手,给出具体的优化思路和涉及到的关键代码逻辑。
16.6万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

AFNetworking处理复杂网络场景的实现原理

  1. 网络切换
    • AFNetworking 通过 AFNetworkReachabilityManager 类来监听网络状态变化。它利用系统提供的 SCNetworkReachability API,通过注册回调函数,当网络状态(如从 WiFi 切换到蜂窝网络,或网络连接断开再恢复)发生改变时,AFNetworkReachabilityManager 会收到通知。
    • 当网络状态变化时,AFNetworking 会重新评估请求队列中的请求,对于正在进行的请求,会根据配置决定是否取消或继续。例如,如果配置为允许跨网络切换继续请求,且新网络可用,请求可能会继续执行。
  2. 请求超时重连
    • AFNetworking 为每个请求设置了超时时间,默认超时时间是 60 秒(可通过 AFURLSessionManagerrequestSerializertimeoutInterval 属性进行设置)。
    • 当请求超时时,AFNetworking 会调用 NSURLSession 的相关方法取消当前请求。如果配置了重连策略(例如 AFHTTPRequestOperation 中有相关设置),则会按照重连策略(如固定次数重连、指数退避重连等)重新发起请求。例如指数退避重连,每次重连的间隔时间会以指数形式增长,以避免短时间内过多无效请求对服务器造成压力。
  3. 数据缓存
    • AFNetworking 提供了 AFURLResponseSerialization 相关类来处理数据缓存。AFImageResponseSerializer 用于图片缓存,AFJSONResponseSerializer 等用于其他类型数据缓存。
    • 缓存机制基于 NSURLCache,当请求返回数据时,AFNetworking 会根据请求的 URL 和缓存策略(如 NSURLRequestUseProtocolCachePolicyNSURLRequestReloadIgnoringLocalCacheData 等)决定是否缓存数据。如果缓存,会将数据存储在 NSURLCache 中,下次相同请求到来时,优先从缓存中读取数据,减少网络请求开销。

AFNetworking可优化点

  1. 网络切换
    • 优化点:网络切换时可能存在请求处理不够智能的情况。例如,在某些场景下,即使网络已切换到新的可用网络,但请求可能由于一些内部状态问题未能及时恢复,导致用户体验不佳。
    • 原因AFNetworkReachabilityManager 虽然能监听网络状态变化,但请求队列和请求状态管理在复杂场景下可能不够完善,没有充分考虑到不同类型请求对网络切换的适应能力。
  2. 请求超时重连
    • 优化点:重连策略相对固定,不能根据不同业务场景灵活调整。例如,对于一些对实时性要求高的业务,固定次数重连和指数退避重连可能无法满足需求,可能需要更复杂的动态重连策略。
    • 原因:当前 AFNetworking 的重连策略是基于通用场景设计,没有针对特定业务需求提供足够的灵活性接口。
  3. 数据缓存
    • 优化点:缓存管理不够精细化。例如,缓存数据的有效期管理相对简单,没有考虑到不同数据的重要性和时效性差异。另外,缓存数据的清理策略可能不够高效,可能导致缓存占用过多内存。
    • 原因NSURLCache 提供的接口相对基础,AFNetworking 在此基础上没有进一步完善更符合业务需求的缓存管理机制。

优化思路及关键代码逻辑

  1. 网络切换优化
    • 优化思路:增强请求队列和请求状态管理,在网络切换时更准确地判断哪些请求可以继续,哪些需要重新发起。可以为请求添加更多属性,如请求优先级、是否可在网络切换时继续等。
    • 关键代码逻辑:在 AFURLSessionManager 类中,修改 task:didCompleteWithError: 方法,在网络切换后重新评估请求状态。例如:
- (void)task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    if (error && [AFNetworkReachabilityManager sharedManager].isReachable) {
        // 判断请求是否可在网络切换后继续
        if ([self.requests[task] valueForKey:@"shouldResumeAfterNetworkChange"]) {
            // 重新发起请求
            NSURLRequest *request = [self.requests[task] copy];
            NSURLSessionDataTask *newTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                // 处理新请求的回调
            }];
            [newTask resume];
        }
    }
    // 原方法其他逻辑
}
  1. 请求超时重连优化
    • 优化思路:提供更灵活的重连策略接口,允许开发者根据业务需求自定义重连逻辑。例如,创建一个协议 AFCustomRetryPolicy,开发者可以实现该协议来自定义重连策略。
    • 关键代码逻辑:在 AFURLSessionManager 类中,添加一个属性用于存储自定义重连策略对象,修改 task:didCompleteWithError: 方法来使用自定义重连策略。
// 定义协议
@protocol AFCustomRetryPolicy <NSObject>
- (BOOL)shouldRetryRequest:(NSURLRequest *)request withError:(NSError *)error retryCount:(NSUInteger)retryCount;
- (NSTimeInterval)retryIntervalForRequest:(NSURLRequest *)request withError:(NSError *)error retryCount:(NSUInteger)retryCount;
@end

// 在AFURLSessionManager类中添加属性
@property (nonatomic, strong) id<AFCustomRetryPolicy> customRetryPolicy;

// 修改task:didCompleteWithError:方法
- (void)task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    if (error && error.code == NSURLErrorTimedOut) {
        NSUInteger retryCount = [self.requests[task] valueForKey:@"retryCount"] ?: 0;
        if ([self.customRetryPolicy shouldRetryRequest:self.requests[task] withError:error retryCount:retryCount]) {
            NSTimeInterval retryInterval = [self.customRetryPolicy retryIntervalForRequest:self.requests[task] withError:error retryCount:retryCount];
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(retryInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                NSURLRequest *request = [self.requests[task] copy];
                NSURLSessionDataTask *newTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                    // 处理新请求的回调
                }];
                [newTask resume];
                [self.requests[task] setValue:@(retryCount + 1) forKey:@"retryCount"];
            });
        }
    }
    // 原方法其他逻辑
}
  1. 数据缓存优化
    • 优化思路:实现更精细化的缓存管理,为缓存数据添加更多元信息,如重要性级别、有效期等。优化缓存清理策略,根据数据的重要性和有效期进行清理。
    • 关键代码逻辑:创建一个自定义的缓存类 AFCustomCache 继承自 NSURLCache,重写 storeCachedResponse:forRequest:cachedResponseForRequest: 方法。
@interface AFCustomCache : NSURLCache
@end

@implementation AFCustomCache
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request {
    // 添加元信息,如有效期
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:cachedResponse.userInfo];
    userInfo[@"expiryDate"] = [NSDate dateWithTimeIntervalSinceNow:3600]; // 假设有效期1小时
    NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];
    [super storeCachedResponse:newCachedResponse forRequest:request];
}

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
    NSCachedURLResponse *cachedResponse = [super cachedResponseForRequest:request];
    if (cachedResponse) {
        NSDate *expiryDate = cachedResponse.userInfo[@"expiryDate"];
        if (expiryDate && [expiryDate compare:[NSDate date]] == NSOrderedAscending) {
            // 数据已过期,清理缓存
            [self removeCachedResponseForRequest:request];
            return nil;
        }
    }
    return cachedResponse;
}
@end

然后在项目中使用自定义缓存类:

AFCustomCache *customCache = [[AFCustomCache alloc] initWithMemoryCapacity:10 * 1024 * 1024 diskCapacity:100 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:customCache];