MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C网络请求的高效管理与优化

2021-01-317.3k 阅读

一、网络请求基础

在Objective-C开发中,网络请求是与服务器进行数据交互的关键操作。常用的网络请求方式有GET、POST、PUT、DELETE等。

GET请求:主要用于从服务器获取数据。请求参数直接附加在URL后面,例如:

NSString *urlString = [NSString stringWithFormat:@"https://example.com/api?param1=value1&param2=value2"];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"GET Response: %@", responseString);
    } else {
        NSLog(@"GET Error: %@", error);
    }
}];
[task resume];

POST请求:通常用于向服务器提交数据,比如用户注册、登录等场景。数据一般放在请求体中:

NSString *urlString = @"https://example.com/api";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *postString = @"param1=value1&param2=value2";
request.HTTPBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"POST Response: %@", responseString);
    } else {
        NSLog(@"POST Error: %@", error);
    }
}];
[task resume];

二、网络请求管理框架

  1. AFNetworking
    • AFNetworking是一款广泛使用的网络请求框架,它提供了简洁易用的API,支持多种请求方式,并且对缓存、认证等功能有很好的支持。
    • 初始化AFHTTPSessionManager:
#import <AFNetworking/AFNetworking.h>
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
  • GET请求示例:
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"AFNetworking GET Success: %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"AFNetworking GET Error: %@", error);
}];
  • POST请求示例:
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"AFNetworking POST Success: %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"AFNetworking POST Error: %@", error);
}];
  1. Alamofire
    • Alamofire也是一款流行的网络框架,它基于AFNetworking进行了更高层次的封装,使得网络请求代码更加简洁优雅。
    • GET请求示例:
#import <Alamofire/Alamofire.h>
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[Alamofire request:url method:.get parameters:parameters encoding:URLEncoding.default headers:nil completionHandler:^(AFHTTPRequestOperationManager * _Nonnull manager, NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
    if (!error && responseObject) {
        NSLog(@"Alamofire GET Success: %@", responseObject);
    } else {
        NSLog(@"Alamofire GET Error: %@", error);
    }
}];
  • POST请求示例:
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[Alamofire request:url method:.post parameters:parameters encoding:URLEncoding.default headers:nil completionHandler:^(AFHTTPRequestOperationManager * _Nonnull manager, NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
    if (!error && responseObject) {
        NSLog(@"Alamofire POST Success: %@", responseObject);
    } else {
        NSLog(@"Alamofire POST Error: %@", error);
    }
}];

三、网络请求的高效管理

  1. 请求队列管理
    • 在复杂的应用中,可能会同时发起多个网络请求。合理管理请求队列可以避免资源过度消耗。以AFNetworking为例,可以使用AFURLSessionManager的NSURLSession来管理任务队列。
    • 创建一个AFURLSessionManager:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
  • 然后可以将多个网络请求任务添加到这个managerNSURLSession中,AFNetworking会自动根据系统资源情况进行任务调度。例如:
NSURL *url1 = [NSURL URLWithString:@"https://example.com/api1"];
NSURLRequest *request1 = [NSURLRequest requestWithURL:url1];
NSURLSessionDataTask *task1 = [manager dataTaskWithRequest:request1 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        // 处理响应
    }
}];
NSURL *url2 = [NSURL URLWithString:@"https://example.com/api2"];
NSURLRequest *request2 = [NSURLRequest requestWithURL:url2];
NSURLSessionDataTask *task2 = [manager dataTaskWithRequest:request2 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        // 处理响应
    }
}];
[task1 resume];
[task2 resume];
  1. 请求优先级设置
    • 对于一些关键的网络请求,如用户登录、支付等,需要设置较高的优先级。在AFNetworking中,可以通过设置NSURLSessionDataTaskpriority属性来设置请求优先级。
    • 例如:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/payment"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        // 处理支付响应
    }
}];
task.priority = NSURLSessionTaskPriorityHigh;
[task resume];
  1. 网络状态监测
    • 实时了解网络状态对于优化网络请求非常重要。AFNetworking提供了网络状态监测功能。
    • 首先,引入AFNetworkReachabilityManager:
#import <AFNetworking/AFNetworkReachabilityManager.h>
AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
[reachabilityManager startMonitoring];
[reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    switch (status) {
        case AFNetworkReachabilityStatusReachableViaWWAN:
            NSLog(@"Reachable via WWAN");
            break;
        case AFNetworkReachabilityStatusReachableViaWiFi:
            NSLog(@"Reachable via WiFi");
            break;
        case AFNetworkReachabilityStatusNotReachable:
            NSLog(@"Not reachable");
            break;
        default:
            break;
    }
}];
  • 当网络状态发生变化时,可以根据不同的状态采取不同的网络请求策略,比如在网络不可达时暂停一些非关键的请求,或者在切换到蜂窝网络时调整请求频率等。

四、网络请求优化策略

  1. 数据压缩
    • 在网络请求中,数据传输量是影响性能的一个重要因素。启用数据压缩可以显著减少传输的数据量。在AFNetworking中,可以通过设置NSURLSessionConfigurationHTTPShouldUsePipeliningHTTPCompressionMethod属性来启用数据压缩。
    • 例如:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPShouldUsePipelining = YES;
configuration.HTTPCompressionMethod = NSURLRequestCompressionMethodGzip;
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
  1. 缓存策略
    • 合理使用缓存可以避免重复请求相同的数据,提高应用的响应速度。AFNetworking提供了多种缓存策略,如NSURLRequestUseProtocolCachePolicyNSURLRequestReloadIgnoringLocalCacheData等。
    • 使用NSURLRequestUseProtocolCachePolicy策略示例:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (!error && data) {
        // 处理响应
    }
}];
[task resume];
  • 这个策略会根据服务器返回的缓存控制头信息来决定是否使用缓存数据。如果服务器设置了合适的缓存时间,AFNetworking会在缓存有效期内直接使用缓存数据,而不会再次发起网络请求。
  1. 优化请求频率
    • 在一些情况下,可能会频繁发起网络请求,这会消耗大量的网络资源和电量。例如,在一个实时更新数据的应用中,如果每秒都发起一次请求获取最新数据,可能会导致性能问题。可以通过设置合理的请求间隔来优化请求频率。
    • 比如,使用NSTimer来控制请求频率:
__block NSInteger requestCount = 0;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    NSString *urlString = [NSString stringWithFormat:@"https://example.com/api?param=%ld", (long)requestCount];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error && data) {
            // 处理响应
        }
    }];
    [task resume];
    requestCount++;
}];
  • 这里设置了每10秒发起一次网络请求,根据实际应用场景,可以调整这个时间间隔,以达到最优的性能和数据更新频率平衡。

五、错误处理与重试机制

  1. 错误处理
    • 在网络请求过程中,可能会遇到各种错误,如网络连接失败、服务器响应错误等。正确处理这些错误对于提升用户体验至关重要。在AFNetworking的failure回调中,可以获取详细的错误信息。
    • 例如:
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"AFNetworking POST Success: %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSInteger statusCode = [(NSHTTPURLResponse *)task.response statusCode];
    if (statusCode == 400) {
        NSLog(@"Bad Request Error: %@", error);
    } else if (statusCode == 401) {
        NSLog(@"Unauthorized Error: %@", error);
    } else if (statusCode == 500) {
        NSLog(@"Internal Server Error: %@", error);
    } else {
        NSLog(@"Other Error: %@", error);
    }
}];
  1. 重试机制
    • 对于一些由于临时网络问题导致的请求失败,可以设置重试机制。在AFNetworking中,可以通过自定义一个重试逻辑来实现。
    • 例如:
NSInteger retryCount = 0;
void (^retryBlock)(void) = ^{
    if (retryCount < 3) {
        NSString *url = @"https://example.com/api";
        NSURL *nsUrl = [NSURL URLWithString:url];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nsUrl];
        request.HTTPMethod = @"POST";
        // 设置请求体等
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (!error && data) {
                // 处理响应
            } else {
                retryCount++;
                retryBlock();
            }
        }];
        [task resume];
    }
};
retryBlock();
  • 这里设置了最多重试3次,如果请求失败,会在重试次数未达到上限时再次发起请求。

六、与服务器端的协同优化

  1. 服务器端优化
    • 服务器端的性能优化对于网络请求的高效性同样重要。服务器可以优化数据库查询、使用缓存技术等。例如,在服务器端使用Memcached或Redis等缓存系统,对于一些频繁请求且不经常变化的数据,直接从缓存中返回,减少数据库查询时间,从而提高响应速度。
    • 另外,服务器端可以对API进行优化,减少不必要的计算和数据处理。例如,对于只需要部分数据的请求,服务器只返回所需的字段,而不是整个数据集,这样可以减少数据传输量。
  2. 数据格式协商
    • 客户端和服务器端可以协商使用更高效的数据格式。例如,JSON格式虽然广泛使用,但对于一些数据量较大且结构复杂的场景,Protocol Buffers或MessagePack等二进制数据格式可能更加高效。这些格式在序列化和反序列化时速度更快,并且占用的空间更小。
    • 在Objective-C中,如果要使用Protocol Buffers,需要先定义.proto文件,然后使用protoc工具生成Objective-C代码。例如,定义一个简单的.proto文件:
syntax = "proto3";
message User {
    string name = 1;
    int32 age = 2;
}
  • 生成Objective-C代码后,在客户端可以这样使用:
#import "User.pbobjc.h"
User *user = [User message];
user.name = @"John";
user.age = 30;
NSData *data = [user data];
// 发送data到服务器
  • 在服务器端,根据相应的语言(如Java、Python等)解析和处理这些数据,通过这种方式可以优化数据传输和处理效率。

七、安全性优化

  1. HTTPS使用
    • 使用HTTPS协议可以确保网络请求的安全性,防止数据被窃取或篡改。在Objective-C中,AFNetworking默认支持HTTPS请求。但是,如果服务器使用的是自签名证书,需要进行一些额外的配置。
    • 例如,在AFNetworking中信任自签名证书:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
manager.securityPolicy = securityPolicy;
  • 不过,在实际应用中,尽量使用由受信任的证书颁发机构颁发的证书,以确保更高的安全性。
  1. 数据加密
    • 除了使用HTTPS,对于一些敏感数据,如用户密码、支付信息等,可以在客户端进行额外的数据加密。在Objective-C中,可以使用CommonCrypto框架进行加密。
    • 例如,使用AES加密:
#import <CommonCrypto/CommonCrypto.h>
NSData *plainTextData = [@"sensitive data" dataUsingEncoding:NSUTF8StringEncoding];
NSData *keyData = [@"16 - byte key" dataUsingEncoding:NSUTF8StringEncoding];
NSData *ivData = [@"16 - byte iv" dataUsingEncoding:NSUTF8StringEncoding];
size_t bufferSize = plainTextData.length + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                      keyData.bytes, keyData.length,
                                      ivData.bytes,
                                      plainTextData.bytes, plainTextData.length,
                                      buffer, bufferSize,
                                      &numBytesEncrypted);
NSData *encryptedData = nil;
if (cryptStatus == kCCSuccess) {
    encryptedData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
} else {
    free(buffer);
}
  • 这样加密后的数据在网络传输过程中更加安全,即使数据被截取,没有密钥也无法解密。

八、性能监测与分析

  1. 使用工具进行监测
    • Instruments是Xcode自带的一款强大的性能监测工具。在网络请求优化中,可以使用Instruments中的Network工具来监测网络流量、请求时间等。
    • 打开Instruments,选择Network模板,然后运行应用。在应用进行网络请求时,Network工具会实时显示每个请求的详细信息,如请求URL、请求方法、响应时间、数据传输量等。通过分析这些数据,可以找出性能瓶颈,例如哪些请求响应时间过长,哪些请求传输的数据量过大等。
  2. 自定义性能指标
    • 除了使用Instruments,还可以在代码中自定义一些性能指标。例如,记录每个网络请求的开始时间和结束时间,计算请求的耗时。
    • 例如:
NSDate *startDate = [NSDate date];
NSString *url = @"https://example.com/api";
NSDictionary *parameters = @{@"param1": @"value1", @"param2": @"value2"};
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSDate *endDate = [NSDate date];
    NSTimeInterval duration = [endDate timeIntervalSinceDate:startDate];
    NSLog(@"Request Duration: %f seconds", duration);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"AFNetworking GET Error: %@", error);
}];
  • 通过收集和分析这些自定义的性能指标,可以更深入地了解网络请求的性能状况,为进一步优化提供依据。

通过以上对Objective - C网络请求的高效管理与优化的各个方面的阐述,包括基础请求、管理框架、高效管理策略、优化策略、错误处理、安全性优化以及性能监测等,开发者可以构建出更加高效、稳定和安全的网络请求系统,提升应用的整体性能和用户体验。