MST

星途 面试题库

面试题:Objective-C断点续传在复杂网络环境下的健壮性设计

在复杂网络环境如网络波动、丢包频繁的情况下,如何设计一个健壮的Objective-C断点续传系统。请从错误处理机制、重试策略、数据一致性校验等方面详细阐述,并说明如何通过代码实现这些机制,确保在各种复杂网络场景下断点续传都能可靠完成。
30.9万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

错误处理机制

  1. 网络请求错误:在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) {
            // 处理无网络连接错误
        }
    }
}
  1. 文件操作错误:在读写文件时,使用NSError参数捕获错误。例如,写入文件失败可能是因为磁盘空间不足等原因。
NSError *fileError;
BOOL success = [data writeToFile:filePath options:NSDataWritingAtomic error:&fileError];
if (!success) {
    // 处理文件写入错误
}

重试策略

  1. 固定重试次数:设定一个固定的重试次数,如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];
}
  1. 指数退避重试:随着重试次数增加,等待时间呈指数增长,如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];
}

数据一致性校验

  1. 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 {
    // 数据不一致,重新下载
}
  1. 文件大小校验:在下载前获取服务器文件大小,下载完成后对比本地文件大小是否一致。
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];

断点续传实现

  1. 记录下载进度:使用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;
}
  1. 断点续传请求:在网络中断后,根据记录的已下载字节数,设置NSMutableURLRequestRange头字段,从断点处继续下载。
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断点续传系统能可靠完成任务。