Objective-C网络编程与NSURLSession应用
一、NSURLSession 简介
在Objective-C的网络编程中,NSURLSession
是苹果公司在iOS 7.0和OS X 10.9引入的强大网络框架,用于替代旧的NSURLConnection
。NSURLSession
提供了一个简单且强大的方式来处理基于URL的网络请求,包括数据加载、文件下载和上传等操作。它支持多种任务类型,如数据任务、下载任务和上传任务,并且对连接的管理和复用有很好的优化,能有效提高网络请求的效率。
NSURLSession
是基于任务(NSURLSessionTask
)的模型。一个NSURLSession
对象可以创建多个不同类型的任务,每个任务负责处理一个具体的网络请求。NSURLSession
的设计使得代码结构更加清晰,便于管理和维护不同类型的网络操作。
二、NSURLSession 的创建与配置
2.1 创建NSURLSessionConfiguration对象
在使用NSURLSession
之前,首先需要创建一个NSURLSessionConfiguration
对象。这个对象用于配置NSURLSession
的各种属性,例如请求超时时间、缓存策略、认证信息等。NSURLSessionConfiguration
有几种不同的子类,以满足不同的需求:
- NSURLSessionConfiguration.default:默认配置,适用于大多数常见的网络请求场景。它会使用系统默认的缓存策略、超时时间等设置。
- NSURLSessionConfiguration.ephemeral:临时配置,这种配置下的
NSURLSession
不会将任何数据写入磁盘,包括缓存数据、Cookie等。适用于需要临时处理敏感数据的网络请求,请求结束后不会在设备上留下任何相关数据。 - NSURLSessionConfiguration.background:后台配置,用于在应用进入后台时仍能继续执行网络任务。这种配置下的网络任务可以在应用被挂起甚至关闭时,由系统在后台调度执行。
以下是创建不同类型NSURLSessionConfiguration
对象的示例代码:
// 创建默认配置
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
// 创建临时配置
NSURLSessionConfiguration *ephemeralConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
// 创建后台配置
NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.backgroundSession"];
在上述代码中,backgroundSessionConfigurationWithIdentifier:
方法需要传入一个唯一的标识符,用于标识这个后台会话。这个标识符在应用的不同启动周期中用于关联同一个后台会话。
2.2 创建NSURLSession对象
创建好NSURLSessionConfiguration
对象后,就可以使用它来创建NSURLSession
对象。NSURLSession
有两种常见的创建方式:
- 使用共享会话:
NSURLSession
提供了一个共享的单例对象[NSURLSession sharedSession]
,它使用默认的配置。共享会话适用于不需要特殊配置的简单网络请求场景,例如大多数应用内的常规数据获取。
NSURLSession *sharedSession = [NSURLSession sharedSession];
- 自定义配置的会话:通过传入
NSURLSessionConfiguration
对象来创建具有特定配置的NSURLSession
对象。
NSURLSession *customSession = [NSURLSession sessionWithConfiguration:defaultConfigObject];
在创建自定义配置的会话时,除了传入NSURLSessionConfiguration
对象,还可以传入一个委托对象(NSURLSessionDelegate
或其相关子类的对象),用于处理网络请求过程中的各种事件,如认证挑战、数据接收等。如果不传入委托对象,则会话不会处理这些事件,可能导致请求失败。
三、NSURLSession 数据任务
3.1 基本数据任务
数据任务(NSURLSessionDataTask
)用于从指定的URL加载数据,并将响应数据以NSData
的形式返回。这是最常见的网络请求类型之一,适用于获取JSON、XML等格式的数据。
以下是一个简单的数据任务示例,用于获取一个URL的内容:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"请求失败: %@", error);
} else {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"响应数据: %@", responseString);
}
}];
[dataTask resume];
在上述代码中:
- 首先创建一个
NSURL
对象,指定请求的URL。 - 然后通过
NSURL
创建一个NSURLRequest
对象,NSURLRequest
可以对请求进行更多的设置,如请求方法(GET、POST等)、请求头信息等。这里使用默认的GET请求。 - 使用共享会话创建一个
NSURLSessionDataTask
对象,并传入NSURLRequest
对象。completionHandler
是一个块(block),在任务完成后会被调用,通过这个块可以获取到响应数据(data
)、响应对象(response
)以及可能发生的错误(error
)。 - 最后调用
resume
方法启动任务,如果不调用resume
,任务不会开始执行。
3.2 带参数的POST请求数据任务
对于需要传递参数的POST请求,可以通过修改NSURLRequest
的属性来实现。以下是一个发送POST请求并传递JSON格式参数的示例:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/submit"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSDictionary *parameters = @{@"key1": @"value1", @"key2": @"value2"};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error];
if (error) {
NSLog(@"JSON序列化错误: %@", error);
return;
}
request.HTTPBody = jsonData;
request.additionalHeaders = @{@"Content-Type": @"application/json"};
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"请求失败: %@", error);
} else {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"响应数据: %@", responseString);
}
}];
[dataTask resume];
在这个示例中:
- 创建一个
NSMutableURLRequest
对象,因为需要修改请求的属性,如请求方法和请求体。 - 设置请求方法为
POST
。 - 将参数以字典的形式定义,然后使用
NSJSONSerialization
将字典转换为JSON格式的数据。 - 将JSON数据设置为请求体,并添加
Content-Type
头信息,告诉服务器请求数据的格式是JSON。 - 后续创建数据任务和处理响应的过程与GET请求类似。
四、NSURLSession 下载任务
4.1 简单下载任务
下载任务(NSURLSessionDownloadTask
)用于从指定的URL下载文件。它会将文件下载到一个临时位置,任务完成后,需要将文件移动到最终的目标位置。
以下是一个简单的下载任务示例:
NSURL *url = [NSURL URLWithString:@"https://example.com/file.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"下载失败: %@", error);
} else {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectoryURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *destinationURL = [documentsDirectoryURL URLByAppendingPathComponent:response.suggestedFilename];
NSError *moveError;
[fileManager moveItemAtURL:location toURL:destinationURL error:&moveError];
if (moveError) {
NSLog(@"移动文件失败: %@", moveError);
} else {
NSLog(@"文件下载并保存成功: %@", destinationURL);
}
}
}];
[downloadTask resume];
在上述代码中:
- 创建
NSURL
和NSURLRequest
对象,指定下载的URL。 - 使用共享会话创建
NSURLSessionDownloadTask
对象,completionHandler
块在下载完成后被调用。 - 在
completionHandler
中,首先获取文件管理器(NSFileManager
),然后获取应用的文档目录URL。 - 使用
response.suggestedFilename
获取服务器建议的文件名,并将其附加到文档目录URL后,得到目标文件的URL。 - 最后使用
fileManager
的moveItemAtURL:toURL:error:
方法将临时位置的下载文件移动到目标位置。
4.2 下载进度跟踪
在下载过程中,有时需要跟踪下载进度,以便向用户展示下载的实时状态。可以通过实现NSURLSessionDownloadDelegate
协议来获取下载进度信息。
首先,创建NSURLSession
时需要传入一个遵守NSURLSessionDownloadDelegate
协议的委托对象:
@interface DownloadManager : NSObject <NSURLSessionDownloadDelegate>
@end
@implementation DownloadManager
// 实现下载进度跟踪方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
float progress = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;
NSLog(@"下载进度: %.2f%%", progress * 100);
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/file.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
DownloadManager *downloadManager = [[DownloadManager alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:downloadManager delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
[downloadTask resume];
在上述代码中:
- 定义了一个
DownloadManager
类,实现了NSURLSessionDownloadDelegate
协议的URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
方法。 - 在该方法中,通过计算已下载字节数与总字节数的比例,得到下载进度,并打印输出。
- 创建
NSURLSession
时,传入DownloadManager
对象作为委托,这样在下载过程中会调用委托方法来更新下载进度。
五、NSURLSession 上传任务
5.1 简单上传任务
上传任务(NSURLSessionUploadTask
)用于将本地数据上传到服务器。可以上传NSData
对象,例如图片数据、文本数据等。
以下是一个简单的上传任务示例,将本地的一个文本文件内容上传到服务器:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"txt"];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:fileData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"上传失败: %@", error);
} else {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"响应数据: %@", responseString);
}
}];
[uploadTask resume];
在上述代码中:
- 创建
NSURL
和NSMutableURLRequest
对象,设置请求方法为POST
。 - 获取本地文本文件的路径,并将文件内容读取为
NSData
对象。 - 使用共享会话创建
NSURLSessionUploadTask
对象,传入请求和要上传的数据。 - 在
completionHandler
块中处理上传完成后的响应,判断是否上传成功,并打印响应数据。
5.2 带进度跟踪的上传任务
与下载任务类似,上传任务也可以跟踪进度。通过实现NSURLSessionTaskDelegate
协议的URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
方法来获取上传进度。
首先,创建一个遵守NSURLSessionTaskDelegate
协议的类:
@interface UploadManager : NSObject <NSURLSessionTaskDelegate>
@end
@implementation UploadManager
// 实现上传进度跟踪方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
float progress = (float)totalBytesSent / (float)totalBytesExpectedToSend;
NSLog(@"上传进度: %.2f%%", progress * 100);
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/api/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"txt"];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
UploadManager *uploadManager = [[UploadManager alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:uploadManager delegateQueue:nil];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:fileData];
[uploadTask resume];
在上述代码中:
- 定义了
UploadManager
类,实现了NSURLSessionTaskDelegate
协议的URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
方法,用于计算和打印上传进度。 - 创建
NSURLSession
时,传入UploadManager
对象作为委托,在上传过程中,该委托方法会被调用以更新上传进度。
六、NSURLSession 委托与事件处理
6.1 认证挑战处理
在进行网络请求时,有时服务器会要求进行认证,例如HTTP基本认证。NSURLSession
通过委托方法来处理认证挑战。需要实现NSURLSessionDelegate
协议的URLSession:didReceiveChallenge:completionHandler:
方法。
以下是一个简单的处理HTTP基本认证的示例:
@interface AuthenticationManager : NSObject <NSURLSessionDelegate>
@end
@implementation AuthenticationManager
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]) {
NSString *username = @"yourUsername";
NSString *password = @"yourPassword";
NSURLCredential *credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/protected"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AuthenticationManager *authManager = [[AuthenticationManager alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:authManager delegateQueue:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
在上述代码中:
- 定义了
AuthenticationManager
类,实现了URLSession:didReceiveChallenge:completionHandler:
方法。 - 在方法中,首先判断认证方法是否为HTTP基本认证。如果是,则创建一个包含用户名和密码的
NSURLCredential
对象,并通过completionHandler
传递认证凭证,告诉系统使用该凭证进行认证。如果不是HTTP基本认证,则取消认证挑战。 - 创建
NSURLSession
时,传入AuthenticationManager
对象作为委托,以便在遇到认证挑战时能够正确处理。
6.2 重定向处理
当服务器返回重定向响应(HTTP 301、302等状态码)时,NSURLSession
可以通过委托方法来决定如何处理重定向。需要实现NSURLSessionTaskDelegate
协议的URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
方法。
以下是一个简单的重定向处理示例,默认跟随重定向:
@interface RedirectionManager : NSObject <NSURLSessionTaskDelegate>
@end
@implementation RedirectionManager
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler {
completionHandler(request);
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/redirect"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RedirectionManager *redirectionManager = [[RedirectionManager alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:redirectionManager delegateQueue:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
在上述代码中:
- 定义了
RedirectionManager
类,实现了URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
方法。 - 在方法中,直接通过
completionHandler
返回新的请求,这样NSURLSession
会自动跟随重定向。如果需要自定义重定向行为,可以对新请求进行修改后再返回。 - 创建
NSURLSession
时,传入RedirectionManager
对象作为委托,以处理重定向事件。
七、NSURLSession 与多线程
NSURLSession
在设计上充分考虑了多线程的支持。默认情况下,NSURLSession
的任务会在后台线程中执行,以避免阻塞主线程,保证应用的流畅性。
7.1 使用默认队列
当创建NSURLSession
时,如果不传入delegateQueue
参数,NSURLSession
会使用一个默认的后台队列来执行任务和调用委托方法。例如:
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
在这种情况下,NSURLSession
会在一个系统管理的后台队列中执行任务,当任务完成或发生特定事件(如接收到数据、认证挑战等)时,会在这个后台队列中调用委托方法。如果委托方法中需要更新UI,由于UI更新必须在主线程中进行,所以需要切换到主线程。例如:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
dispatch_async(dispatch_get_main_queue(), ^{
// 更新UI的代码
});
}
7.2 自定义队列
可以通过传入一个自定义的NSOperationQueue
作为delegateQueue
参数,来指定NSURLSession
使用的队列。这样可以更精确地控制任务的执行和委托方法的调用。例如:
NSOperationQueue *customQueue = [[NSOperationQueue alloc] init];
customQueue.maxConcurrentOperationCount = 1; // 设置为串行队列
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:customQueue];
在上述代码中,创建了一个自定义的串行队列,并将其作为delegateQueue
传入NSURLSession
的创建方法。这样,NSURLSession
的任务和委托方法会在这个自定义的串行队列中执行。如果需要并行执行任务,可以适当调整maxConcurrentOperationCount
的值。
八、NSURLSession 的缓存策略
NSURLSession
支持多种缓存策略,通过NSURLRequest
的cachePolicy
属性来设置。常见的缓存策略有以下几种:
8.1 NSURLRequestUseProtocolCachePolicy
这是默认的缓存策略,它遵循协议的规定来处理缓存。对于HTTP请求,它会根据服务器返回的Cache-Control
和Expires
头信息来决定是否使用缓存以及缓存的有效期。如果服务器没有明确的缓存指示,它可能会根据请求方法(GET请求更倾向于使用缓存)和其他因素来决定。
8.2 NSURLRequestReloadIgnoringLocalCacheData
这种策略会忽略本地缓存数据,每次都从服务器重新加载数据。适用于需要获取最新数据的场景,例如实时数据的请求。示例代码如下:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/liveData"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
8.3 NSURLRequestReturnCacheDataElseLoad
这种策略会先尝试从本地缓存中获取数据,如果缓存中没有数据,则从服务器加载。适用于对数据实时性要求不是特别高,且希望在网络不佳时仍能显示部分数据的场景。示例代码如下:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/info"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
8.4 NSURLRequestReturnCacheDataDontLoad
这种策略会只从本地缓存中获取数据,如果缓存中没有数据,则不进行网络加载,直接返回缓存中已有的过期数据(如果有)。适用于完全依赖本地缓存数据,且不希望进行任何网络请求的场景,例如离线应用的部分功能。示例代码如下:
NSURL *url = [NSURL URLWithString:@"https://example.com/api/offlineInfo"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy = NSURLRequestReturnCacheDataDontLoad;
通过合理设置缓存策略,可以在提高应用性能的同时,节省用户的流量,并提供更好的用户体验。
九、NSURLSession 的常见问题与解决方法
9.1 网络请求超时
在网络不稳定或服务器响应缓慢的情况下,可能会出现网络请求超时的问题。可以通过NSURLSessionConfiguration
的timeoutIntervalForRequest
属性来设置请求的超时时间。例如:
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.timeoutIntervalForRequest = 15; // 设置超时时间为15秒
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
如果在设置的超时时间内没有收到服务器的响应,NSURLSession
会调用completionHandler
并传入相应的超时错误。在处理错误时,可以提示用户网络请求超时,并根据应用的逻辑决定是否重新发起请求。
9.2 证书验证失败
当访问使用HTTPS协议的服务器时,如果服务器的证书不被信任(例如自签名证书),可能会导致证书验证失败,网络请求无法继续。可以通过实现NSURLSessionDelegate
协议的URLSession:didReceiveChallenge:completionHandler:
方法来处理证书验证挑战。
对于自签名证书,可以选择信任该证书:
@interface SSLManager : NSObject <NSURLSessionDelegate>
@end
@implementation SSLManager
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/secure"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
SSLManager *sslManager = [[SSLManager alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:sslManager delegateQueue:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
在上述代码中,当遇到服务器信任挑战时,创建一个基于服务器信任的NSURLCredential
对象,并使用该凭证继续请求。需要注意的是,信任自签名证书可能存在安全风险,在实际应用中应谨慎使用,并确保证书的来源可靠。
9.3 内存管理问题
在处理大量数据的网络请求(如大文件的下载或上传)时,可能会遇到内存管理的问题。对于下载任务,NSURLSessionDownloadTask
会将文件下载到临时位置,在任务完成后及时将文件移动到最终位置可以避免内存占用过高。对于数据任务,如果返回的数据量较大,可以考虑分块处理数据,而不是一次性加载全部数据到内存。
例如,在数据任务的委托方法URLSession:dataTask:didReceiveData:
中,可以对数据进行分块处理:
@interface DataHandler : NSObject <NSURLSessionDataDelegate>
@property (nonatomic, strong) NSMutableData *receivedData;
@end
@implementation DataHandler
- (instancetype)init {
self = [super init];
if (self) {
_receivedData = [NSMutableData data];
}
return self;
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
// 这里可以对self.receivedData进行分块处理,例如写入文件等
}
@end
// 创建NSURLSession并传入委托对象
NSURL *url = [NSURL URLWithString:@"https://example.com/largeData"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
DataHandler *dataHandler = [[DataHandler alloc] init];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:dataHandler delegateQueue:nil];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
[dataTask resume];
在上述代码中,使用NSMutableData
逐步接收数据,并可以在适当的时候对其进行分块处理,如写入文件,以避免一次性加载大量数据导致内存问题。
通过解决这些常见问题,可以使基于NSURLSession
的网络编程更加稳定和可靠。