面试题答案
一键面试错误处理机制
- 网络请求错误:在Objective-C中,使用
NSURLSession
进行网络请求时,通过NSURLSessionDataDelegate
的- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
方法捕获错误。如果error
不为nil
,根据error.code
判断错误类型,如网络连接失败、超时等。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error) {
if (error.code == NSURLErrorTimedOut) {
// 处理超时错误
} else if (error.code == NSURLErrorNotConnectedToInternet) {
// 处理无网络连接错误
}
}
}
- 文件操作错误:在读写文件时,使用
NSError
参数捕获错误。例如,写入文件失败可能是因为磁盘空间不足等原因。
NSError *fileError;
BOOL success = [data writeToFile:filePath options:NSDataWritingAtomic error:&fileError];
if (!success) {
// 处理文件写入错误
}
重试策略
- 固定重试次数:设定一个固定的重试次数,如3次。每次重试时等待一定时间,如2秒。
NSInteger retryCount = 0;
while (retryCount < 3) {
// 发起网络请求
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
retryCount++;
if (retryCount < 3) {
[NSThread sleepForTimeInterval:2];
// 重新发起请求
}
} else {
// 处理成功的响应
}
}];
[task resume];
}
- 指数退避重试:随着重试次数增加,等待时间呈指数增长,如2秒、4秒、8秒。
NSInteger retryCount = 0;
while (retryCount < 3) {
NSTimeInterval delay = pow(2, retryCount);
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
retryCount++;
if (retryCount < 3) {
[NSThread sleepForTimeInterval:delay];
// 重新发起请求
}
} else {
// 处理成功的响应
}
}];
[task resume];
}
数据一致性校验
- MD5校验:在服务器端计算文件的MD5值,并在下载完成后,在客户端重新计算下载文件的MD5值,对比两者是否一致。
#import <CommonCrypto/CommonDigest.h>
NSString *md5(NSString *str) {
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), result );
return [NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
}
// 计算下载文件的MD5值并与服务器提供的对比
NSString *downloadedMD5 = md5(downloadedFilePath);
if ([downloadedMD5 isEqualToString:serverMD5]) {
// 数据一致
} else {
// 数据不一致,重新下载
}
- 文件大小校验:在下载前获取服务器文件大小,下载完成后对比本地文件大小是否一致。
NSURL *url = [NSURL URLWithString:@"http://example.com/file"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
long long serverFileSize = [(NSHTTPURLResponse *)response expectedContentLength];
// 下载完成后获取本地文件大小
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:downloadedFilePath error:nil];
long long localFileSize = [fileAttributes fileSize];
if (serverFileSize == localFileSize) {
// 数据一致
} else {
// 数据不一致,重新下载
}
}
}];
[task resume];
断点续传实现
- 记录下载进度:使用
NSURLSessionDownloadTask
的- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
方法记录已下载字节数。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
// 记录已下载字节数到本地文件或内存变量
self.downloadedBytes = totalBytesWritten;
}
- 断点续传请求:在网络中断后,根据记录的已下载字节数,设置
NSMutableURLRequest
的Range
头字段,从断点处继续下载。
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:[NSString stringWithFormat:@"bytes=%lld-", (long long)self.downloadedBytes] forHTTPHeaderField:@"Range"];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
[task resume];
通过上述机制的实现,可以确保在复杂网络场景下,Objective-C断点续传系统能可靠完成任务。