MST

星途 面试题库

面试题:Objective-C的Alamofire网络请求库在大型项目中的优化与架构设计

在一个大型的Objective-C项目中,使用Alamofire作为网络请求库。阐述如何对Alamofire进行封装以提高代码的可维护性和复用性,并且从性能优化角度,说明如何处理大量并发请求、缓存策略以及错误处理机制的设计,结合实际项目经验举例说明。
23.2万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. Alamofire 封装提高可维护性和复用性

  1. 创建网络请求基类
    • 定义一个继承自 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
    
  2. 业务请求分类封装
    • 根据业务模块,创建不同的类继承自 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
    
  3. 使用链式调用风格(可选)
    • 可以进一步优化封装,使用链式调用风格,使代码更易读。例如:
    @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. 性能优化 - 处理大量并发请求

  1. 使用队列控制并发数量
    • 创建一个 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];
    }
    
  2. 请求优先级设置
    • 根据业务需求,为不同的请求设置优先级。例如,用户登录请求优先级高于获取广告数据请求。在 Alamofire 中,可以通过 NSURLSessionDataTaskpriority 属性设置优先级。
    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;
    

3. 性能优化 - 缓存策略

  1. 使用系统缓存
    • Alamofire 支持系统默认的缓存策略。可以通过设置 NSURLRequestcachePolicy 属性来实现。例如,使用 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) {
        // 处理响应
    });
    
  2. 自定义缓存
    • 创建一个本地缓存数据库(如 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);
            }
        });
    }
    

4. 错误处理机制设计

  1. 统一错误处理
    • NetworkManager 的请求完成回调中,对错误进行统一处理。例如,根据 NSErrorcode 判断错误类型,并给出相应的提示。
    - (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);
            }
        });
    }
    
  2. 业务层错误处理
    • 在业务请求类(如 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 缓存策略,减少了不必要的网络请求,提高了响应速度。在错误处理方面,统一处理网络连接错误和超时错误,业务层如订单提交失败时,根据服务器返回的错误码给出具体的错误提示,如库存不足等,提升了用户体验。