1. 合理设置缓冲区大小
- 原则:缓冲区大小设置过小,会导致频繁的I/O操作,增加系统开销;设置过大,会占用过多内存。通常可以根据经验值或者实际测试来确定合适大小,一般网络相关I/O缓冲区设置在8KB - 64KB之间。
- 代码示例:
NSMutableData *buffer = [NSMutableData dataWithLength:8 * 1024]; // 设置8KB缓冲区
NSInputStream *inputStream = [NSInputStream inputStreamWithURL:url];
[inputStream open];
NSInteger bytesRead = [inputStream read:buffer.mutableBytes maxLength:buffer.length];
2. 选择合适的I/O方式
- 同步I/O:简单直接,但会阻塞当前线程,在主线程中使用可能导致界面卡顿。适用于对性能要求不高,代码逻辑简单的场景。
- 异步I/O:
- 使用NSURLSession:iOS7.0引入,支持断点续传,系统自动管理I/O操作,适合网络下载场景。
- 代码示例:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url];
[downloadTask resume];
// 实现代理方法处理下载数据
- (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 didFinishDownloadingToURL:(NSURL *)location {
// 处理下载完成后的文件
}
- **使用GCD**:Grand Central Dispatch提供了强大的异步编程能力,可以将I/O操作放到后台队列执行,避免阻塞主线程。
- **代码示例**:
dispatch_queue_t downloadQueue = dispatch_queue_create("com.example.downloadQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(downloadQueue, ^{
NSInputStream *inputStream = [NSInputStream inputStreamWithURL:url];
[inputStream open];
// 进行数据读取操作
[inputStream close];
});
3. 减少不必要的I/O操作
- 在断点续传中:记录已经下载的字节数,避免重复读取和写入已下载的数据。每次启动续传时,从上次中断的位置开始读取和写入。
- 代码示例:
// 假设已经记录上次下载的偏移量
NSInteger offset = lastDownloadedOffset;
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:localFilePath append:YES];
[outputStream open];
[outputStream seekToEndOfFile];
NSInputStream *inputStream = [NSInputStream inputStreamWithURL:url];
[inputStream open];
[inputStream seekToFileOffset:offset];
NSMutableData *buffer = [NSMutableData dataWithLength:8 * 1024];
NSInteger bytesRead;
while ((bytesRead = [inputStream read:buffer.mutableBytes maxLength:buffer.length]) > 0) {
[outputStream write:buffer.bytes maxLength:bytesRead];
}
[inputStream close];
[outputStream close];
4. 使用缓存机制
- 对于频繁读取的数据:可以使用内存缓存(如NSCache),减少磁盘I/O。在断点续传中,如果某些数据段可能会被多次读取(例如HTTP响应头信息等),可以将其缓存起来。
- 代码示例:
NSCache *cache = [[NSCache alloc] init];
// 假设读取HTTP响应头数据
NSURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
[cache setObject:response forKey:request.URL];
}
// 后续需要再次获取响应头时,先从缓存中查找
NSURLResponse *cachedResponse = [cache objectForKey:request.URL];
if (cachedResponse) {
// 使用缓存数据
} else {
// 重新获取
}