gpt4 book ai didi

ios - 创建内存累积的 AFHTTPRequestOperations 队列

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:06:11 27 4
gpt4 key购买 nike

我刚刚更新到 AFNetworking 2.0,我正在重写我的代码以下载数据并将其插入到核心数据中。

我下载 JSON 数据文件(从 10-200mb 文件不等),将它们写入磁盘,然后将它们传递给后台线程来处理数据。下面是下载 JSON 并将其写入磁盘的代码。如果我只是让它运行(甚至不处理数据),应用程序会耗尽内存,直到它被终止。

我假设当数据进入时,它存储在内存中,但是一旦我保存到磁盘,为什么它会留在内存中?自动释放池不应该处理这个吗?我还将 responseData 和 downloadData 设置为 nil。有什么明显的地方我做错了吗?

@autoreleasepool
{
for(int i = 1; i <= totalPages; i++)
{
NSString *path = ....
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:path]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer =[AFJSONResponseSerializer serializer];

[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//convert dictionary to data
NSData *downloadData = [NSKeyedArchiver archivedDataWithRootObject:responseObject];

//save to disk
NSError *saveError = nil;
if (![fileManager fileExistsAtPath:targetPath isDirectory:false])
{
[downloadData writeToFile:targetPath options:NSDataWritingAtomic error:&saveError];
if (saveError != nil)
{
NSLog(@"Download save failed! Error: %@", [saveError description]);
}
}

responseObject = nil;
downloadData = nil;

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(@"Error: %@", error);
}];
}
[mutableOperations addObject:op];
}

NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:mutableOperations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
DLog(@"%lu of %lu complete", (unsigned long)numberOfFinishedOperations, (unsigned long)totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
DLog(@"All operations in batch complete");
}];

mutableOperations = nil;
[manager.operationQueue addOperations:operations waitUntilFinished:NO];

谢谢!

编辑 #1在我的完整 block 中添加一个 @autoreleasepool 似乎稍微减慢了内存使用量,但它仍然会累积并最终导致应用程序崩溃。

最佳答案

如果您的 JSON 文件真的每个 10-200mb,这肯定会导致内存问题,因为这种请求将在内存中加载响应(而不是将它们流式传输到持久存储)。更糟糕的是,因为您使用的是 JSON,我认为问题是两倍,因为您将把它加载到字典/数组中,这也会占用内存。所以,如果你有四个 100mb 的下载正在进行,你的峰值内存使用量可能是 800mb 的数量级(100mb 用于 NSData 加上 ~100mb 用于数组/字典(可能更大),四个并发请求的四倍)。您可能很快就会耗尽内存。

所以,一些 react :

  1. 在处理如此大的数据量时,您需要使用流式接口(interface)(NSURLConnectionNSURLSessionDataTask,您可以在其中写入数据in,而不是将其保存在内存中;或使用 NSURLSessionDownloadTask 为您执行此操作),将数据直接写入持久存储(而不是试图将其保存在 NSData 在 RAM 中,因为它正在下载)。

    如果你使用NSURLSessionDownloadTask,这真的很简单。如果您需要支持 7.0 之前的 iOS 版本,我不确定 AFNetworking 是否支持将响应直接流式传输到持久存储。我敢打赌您可以编写自己的响应序列化程序来执行此操作,但我还没有尝试过。我总是编写自己的 NSURLConnectionDataDelegate 方法,直接下载到持久存储(例如 like this )。

  2. 你可能不想为此使用 JSON(因为 NSJSONSerialization 会将整个资源加载到内存中,然后将其解析为 NSArray/NSDictionary,也在内存中),而是使用一种适合于对响应进行流式解析的格式(例如 XML),并编写一个解析器将数据存储到您的数据存储(Core Data 或 SQLite)中被解析,而不是试图将整个东西加载到 RAM 中。

    请注意,即使 NSXMLParser 的内存效率也低得惊人(参见 this question )。在XMLPerformance示例,Apple 演示了如何使用更麻烦的 LibXML2最小化 XML 解析器的内存占用。

  3. 顺便说一句,我不知道您的 JSON 是否包含您编码的任何二进制数据(例如 base 64 等),但如果是这样,您可能需要考虑一种二进制传输格式,它不'必须做这个转换。使用 base-64 或 uuencode 或任何可以增加带宽和内存需求的东西。 (如果您处理的不是已编码的二进制数据,请忽略这一点。)

  4. 顺便说一句,您可能希望使用“可达性”来确认用户的连接类型(Wifi 与蜂窝网络),因为通过蜂窝网络下载那么多数据被认为是错误的形式(至少在未经用户许可的情况下) ,不仅是因为速度问题,还有用完运营商每月数据计划过多部分的风险。我什至听说 Apple 历来拒绝试图通过蜂窝网络下载过多数据的应用程序。

关于ios - 创建内存累积的 AFHTTPRequestOperations 队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22231971/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com