面试题答案
一键面试1. Alamofire 封装提高可维护性和复用性
- 创建网络请求基类
- 定义一个继承自
NSObject
的基类,例如NetworkManager
。在这个类中封装通用的 Alamofire 请求配置,如设置公共的请求头、请求超时时间等。
@interface NetworkManager : NSObject + (instancetype)sharedManager; - (NSURLSessionDataTask *)requestWithURL:(NSString *)url method:(Alamofire.HTTPMethod)method parameters:(NSDictionary *)parameters headers:(NSDictionary *)headers completion:(void (^)(id responseObject, NSError *error))completion; @end @implementation NetworkManager + (instancetype)sharedManager { static NetworkManager *manager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[NetworkManager alloc] init]; }); return manager; } - (NSURLSessionDataTask *)requestWithURL:(NSString *)url method:(Alamofire.HTTPMethod)method parameters:(NSDictionary *)parameters headers:(NSDictionary *)headers completion:(void (^)(id responseObject, NSError *error))completion { NSMutableURLRequest *request = [Alamofire.request(url, method: method, parameters: parameters, headers: headers).request mutableCopy]; request.timeoutInterval = 30; // 设置超时时间 // 添加公共请求头 [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; return [Alamofire request:request].responseJSON(completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { if (completion) { completion(responseObject, error); } }); } @end
- 定义一个继承自
- 业务请求分类封装
- 根据业务模块,创建不同的类继承自
NetworkManager
,例如用户模块UserNetworkManager
,商品模块ProductNetworkManager
等。在这些类中定义具体业务的请求方法。
@interface UserNetworkManager : NetworkManager - (NSURLSessionDataTask *)loginWithUsername:(NSString *)username password:(NSString *)password completion:(void (^)(id responseObject, NSError *error))completion; @end @implementation UserNetworkManager - (NSURLSessionDataTask *)loginWithUsername:(NSString *)username password:(NSString *)password completion:(void (^)(id responseObject, NSError *error))completion { NSString *url = @"https://example.com/api/login"; NSDictionary *parameters = @{@"username": username, @"password": password}; return [self requestWithURL:url method:.post parameters:parameters headers:nil completion:completion]; } @end
- 根据业务模块,创建不同的类继承自
- 使用链式调用风格(可选)
- 可以进一步优化封装,使用链式调用风格,使代码更易读。例如:
@interface NetworkRequestBuilder : NSObject - (NetworkRequestBuilder *)url:(NSString *)url; - (NetworkRequestBuilder *)method:(Alamofire.HTTPMethod)method; - (NetworkRequestBuilder *)parameters:(NSDictionary *)parameters; - (NetworkRequestBuilder *)headers:(NSDictionary *)headers; - (NSURLSessionDataTask *)execute:(void (^)(id responseObject, NSError *error))completion; @end @implementation NetworkRequestBuilder { NSString *_url; Alamofire.HTTPMethod _method; NSDictionary *_parameters; NSDictionary *_headers; } - (NetworkRequestBuilder *)url:(NSString *)url { _url = url; return self; } - (NetworkRequestBuilder *)method:(Alamofire.HTTPMethod)method { _method = method; return self; } - (NetworkRequestBuilder *)parameters:(NSDictionary *)parameters { _parameters = parameters; return self; } - (NetworkRequestBuilder *)headers:(NSDictionary *)headers { _headers = headers; return self; } - (NSURLSessionDataTask *)execute:(void (^)(id responseObject, NSError *error))completion { return [[NetworkManager sharedManager] requestWithURL:_url method:_method parameters:_parameters headers:_headers completion:completion]; } @end
- 使用方式:
[[[NetworkRequestBuilder alloc] init] url:@"https://example.com/api/data" method:.get parameters:nil headers:nil execute:^(id responseObject, NSError *error) { // 处理响应 }];
2. 性能优化 - 处理大量并发请求
- 使用队列控制并发数量
- 创建一个
NSOperationQueue
,并设置其最大并发数。例如,设置最大并发数为 5,以避免过多请求占用过多资源。
NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init]; requestQueue.maxConcurrentOperationCount = 5; for (int i = 0; i < 20; i++) { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [[NetworkManager sharedManager] requestWithURL:@"https://example.com/api/data" method:.get parameters:nil headers:nil completion:^(id responseObject, NSError *error) { // 处理响应 }]; }]; [requestQueue addOperation:operation]; }
- 创建一个
- 请求优先级设置
- 根据业务需求,为不同的请求设置优先级。例如,用户登录请求优先级高于获取广告数据请求。在 Alamofire 中,可以通过
NSURLSessionDataTask
的priority
属性设置优先级。
NSURLSessionDataTask *loginTask = [[NetworkManager sharedManager] requestWithURL:@"https://example.com/api/login" method:.post parameters:loginParameters headers:nil completion:^(id responseObject, NSError *error) { // 处理登录响应 }]; loginTask.priority = NSURLSessionTaskPriorityHigh; NSURLSessionDataTask *adTask = [[NetworkManager sharedManager] requestWithURL:@"https://example.com/api/ad" method:.get parameters:nil headers:nil completion:^(id responseObject, NSError *error) { // 处理广告响应 }]; adTask.priority = NSURLSessionTaskPriorityLow;
- 根据业务需求,为不同的请求设置优先级。例如,用户登录请求优先级高于获取广告数据请求。在 Alamofire 中,可以通过
3. 性能优化 - 缓存策略
- 使用系统缓存
- Alamofire 支持系统默认的缓存策略。可以通过设置
NSURLRequest
的cachePolicy
属性来实现。例如,使用NSURLRequestReturnCacheDataElseLoad
策略,优先返回缓存数据,如果缓存数据不存在则发起网络请求。
NSMutableURLRequest *request = [Alamofire.request(url, method: method, parameters: parameters, headers: headers).request mutableCopy]; request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; return [Alamofire request:request].responseJSON(completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { // 处理响应 });
- Alamofire 支持系统默认的缓存策略。可以通过设置
- 自定义缓存
- 创建一个本地缓存数据库(如 SQLite)或使用内存缓存(如
NSCache
)。在请求成功后,将响应数据存储到缓存中,并在下次请求相同 URL 时先检查缓存。 - 以
NSCache
为例:
@interface NetworkCache : NSObject + (instancetype)sharedCache; - (void)setCacheObject:(id)object forURL:(NSString *)url; - (id)cacheObjectForURL:(NSString *)url; @end @implementation NetworkCache + (instancetype)sharedCache { static NetworkCache *cache = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cache = [[NetworkCache alloc] init]; }); return cache; } - (void)setCacheObject:(id)object forURL:(NSString *)url { NSCache *cache = [[NSCache alloc] init]; [cache setObject:object forKey:url]; } - (id)cacheObjectForURL:(NSString *)url { NSCache *cache = [[NSCache alloc] init]; return [cache objectForKey:url]; } @end - (NSURLSessionDataTask *)requestWithURL:(NSString *)url method:(Alamofire.HTTPMethod)method parameters:(NSDictionary *)parameters headers:(NSDictionary *)headers completion:(void (^)(id responseObject, NSError *error))completion { id cachedObject = [[NetworkCache sharedCache] cacheObjectForURL:url]; if (cachedObject) { if (completion) { completion(cachedObject, nil); } return nil; } NSMutableURLRequest *request = [Alamofire.request(url, method: method, parameters: parameters, headers: headers).request mutableCopy]; return [Alamofire request:request].responseJSON(completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { if (responseObject &&!error) { [[NetworkCache sharedCache] setCacheObject:responseObject forURL:url]; } if (completion) { completion(responseObject, error); } }); }
- 创建一个本地缓存数据库(如 SQLite)或使用内存缓存(如
4. 错误处理机制设计
- 统一错误处理
- 在
NetworkManager
的请求完成回调中,对错误进行统一处理。例如,根据NSError
的code
判断错误类型,并给出相应的提示。
- (NSURLSessionDataTask *)requestWithURL:(NSString *)url method:(Alamofire.HTTPMethod)method parameters:(NSDictionary *)parameters headers:(NSDictionary *)headers completion:(void (^)(id responseObject, NSError *error))completion { //... return [Alamofire request:request].responseJSON(completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { if (error) { NSString *errorMessage = @"网络请求失败"; if (error.code == NSURLErrorTimedOut) { errorMessage = @"请求超时,请稍后重试"; } else if (error.code == NSURLErrorNotConnectedToInternet) { errorMessage = @"请检查网络连接"; } UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"错误" message:errorMessage preferredStyle:.alert]; UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:.default handler:nil]; [alertController addAction:okAction]; [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil]; } if (completion) { completion(responseObject, error); } }); }
- 在
- 业务层错误处理
- 在业务请求类(如
UserNetworkManager
)中,可以根据业务逻辑对响应数据进行进一步的错误判断。例如,登录接口返回的状态码不为 200 时,提示用户名或密码错误。
- (NSURLSessionDataTask *)loginWithUsername:(NSString *)username password:(NSString *)password completion:(void (^)(id responseObject, NSError *error))completion { //... return [self requestWithURL:url method:.post parameters:parameters headers:nil completion:^(id responseObject, NSError *error) { if (!error) { NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; if (statusCode!= 200) { error = [NSError errorWithDomain:@"UserLoginErrorDomain" code:statusCode userInfo:@{NSLocalizedDescriptionKey: @"用户名或密码错误"}]; } } if (completion) { completion(responseObject, error); } }]; }
- 在业务请求类(如
实际项目经验举例
在一个电商项目中,使用上述封装方法。通过 NetworkManager
统一配置请求头和超时时间,不同业务模块(如商品展示、用户订单等)有各自的网络请求类。在处理商品图片加载时,面临大量并发请求,通过设置 NSOperationQueue
的最大并发数为 3,避免了因过多请求导致的卡顿。同时,对商品列表数据采用了 NSURLRequestReturnCacheDataElseLoad
缓存策略,减少了不必要的网络请求,提高了响应速度。在错误处理方面,统一处理网络连接错误和超时错误,业务层如订单提交失败时,根据服务器返回的错误码给出具体的错误提示,如库存不足等,提升了用户体验。