将大量数据保存到核心数据会导致应用程序因内存问题而终止



我正在将大量项目下载到 NSArray 中,因为我需要将所有项目都放在本地以供脱机使用,一旦数据在 NSURLSession 竞争处理程序中下载到 NSArray 我的应用程序的内存使用量相当适中,约为 120 MB,但是当我开始循环使用此 NSArray 将数据插入核心数据并将其保存在本地时,内存峰值达到 2 GB非常快,然后应用程序由于内存问题而终止。我已经尝试将 NSArray 拆分为数组的 NSArray 以尝试在将每个批次保存到磁盘后释放内存,但这也无济于事,所以我一定错过了一些东西。我做错了什么?我需要保持较低的内存占用空间,以便我可以下载数据,并且延迟加载不是一个选项,只下载所需的内容等,因为我必须提供离线场景,所以我绝对必须在本地拥有数据。

总之

循环的完成处理程序启动时的内存使用量约为 120 MB 然后它迅速增加到 2 GB,应用程序被终止 应用始终位于前台

我正在附加下面的代码,用于下载并保存数据

+ (void)fetchTillDataAll:(int)tillId :(int)startAtRow :(int)takeNoOfRows {  
if ([NWTillHelper isDebug] == 1) {  
NSLog(@"WebServices:fetchTillDataAll:tillId = %d, startAtRow = %d, takeNoOfRows = %d", tillId, startAtRow, takeNoOfRows);  
}  
NSString *finalURL = [NSString stringWithFormat:@"https://host.domain.com/api/foo/bar];  
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:finalURL]  
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {  
if (error != nil) {  
if ([NWTillHelper isDebug] == 1) {  
NSLog(@"WebServices:fetchTillDataAll:Transport error %@", error);  
}  
} else {  
NSHTTPURLResponse *responseHTTP;  
responseHTTP = (NSHTTPURLResponse *) response;  
if(responseHTTP.statusCode != 200) {  
if ([NWTillHelper isDebug] == 1) {  
NSLog(@"WebServices:fetchTillDataAll:Server Error %d", (int) responseHTTP.statusCode);  
}  
} else {  
NSArray *tillBasicDataArray = [NSJSONSerialization JSONObjectWithData:data  
                                     options:0  
                                       error:NULL];  
if ([NWTillHelper isDebug] == 1) {  
NSLog(@"WebServices:fetchTillDataAll:tillBasicDataArray count = %lu", (unsigned long)[tillBasicDataArray count]);  
NSLog(@"WebServices:fetchTillDataAll:tillBasicDataArray looks like %@",tillBasicDataArray);  
}  
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];  

NSPersistentContainer *container = appDelegate.persistentContainer;  
NSArray *arrayOfArrays = [NWTillHelper splitIntoArraysOfBatchSize:tillBasicDataArray :1000];  
for(NSArray *batch in arrayOfArrays) {  
[container performBackgroundTask:^(NSManagedObjectContext *context ) {  
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;  
NSDictionary *tillBasicDataDict = Nil;  
/  
/  
for (id element in batch){  
tillBasicDataDict = element;  
NSString *itemId = [tillBasicDataDict objectForKey:@"itemId"];  
NSString *brandId = [tillBasicDataDict objectForKey:@"companyId"];  
NSString *languageId = [tillBasicDataDict objectForKey:@"languageCode"];  
NSString *colorCode = [NSString stringWithFormat:@"%@", [tillBasicDataDict objectForKey:@"colorCode"]];  
NSString *discountable = [tillBasicDataDict objectForKey:@"discountable"];  
NSString *exchangeable = [tillBasicDataDict objectForKey:@"exchangeable"];  
NSString *noos14 = [tillBasicDataDict objectForKey:@"noos14"];  
NSString *sizeCode = [NSString stringWithFormat:@"%@", [tillBasicDataDict objectForKey:@"sizeCode"]];  
NSString *taxGroup = [tillBasicDataDict objectForKey:@"taxGroupId"];  
NSString *taxRegion = [tillBasicDataDict objectForKey:@"taxRegion"];  
NSString *tradeItemDesc = [tillBasicDataDict objectForKey:@"tradeItemDesc"];  
NSString *withTax = [tillBasicDataDict objectForKey:@"withTax"];  
NSString *status = [tillBasicDataDict objectForKey:@"status"];  
/  

NSManagedObject *newPimItem = Nil;  
newPimItem = [NSEntityDescription  
 insertNewObjectForEntityForName:@"TillData"  
 inManagedObjectContext:context];  
[newPimItem setValue:itemId forKey:@"itemId"];  
[newPimItem setValue:brandId forKey:@"brandId"];  
[newPimItem setValue:languageId forKey:@"languageCode"];  
[newPimItem setValue:colorCode forKey:@"colorCode"];  
[newPimItem setValue:discountable forKey:@"discountable"];  
[newPimItem setValue:exchangeable forKey:@"exchangeable"];  
[newPimItem setValue:noos14 forKey:@"noos14"];  
[newPimItem setValue:sizeCode forKey:@"sizeCode"];  
[newPimItem setValue:[NSNumber numberWithInt:[taxGroup intValue]] forKey:@"taxGroup"];  
[newPimItem setValue:taxRegion forKey:@"taxRegion"];  
[newPimItem setValue:tradeItemDesc forKey:@"tradeItemDesc"];  
[newPimItem setValue:[NSNumber numberWithInt:[withTax intValue]] forKey:@"withTax"];  
[newPimItem setValue:[NSNumber numberWithInt:[status intValue]] forKey:@"status"];  
if ([NWTillHelper isDebug] == 1) {  
NSLog(@"WebServices:fetchTillDataAll:ItemId in loop = %@", itemId);  
NSLog(@"WebServices:fetchTillDataAll:newPimItem = %@", newPimItem);  
NSLog(@"WebServices:fetchTillDataAll:CoreData error = %@", error);  
}  
}  
NSError *error = nil;  
if (![context save:&error]) {  
NSLog(@"Failure to save context: %@n%@", [error localizedDescription], [error userInfo]);  
abort();  
} else {  
NSUserDefaults *tillUserDefaults = [NSUserDefaults standardUserDefaults];  
[tillUserDefaults setInteger:1 forKey:@"hasTillData"];  
[tillUserDefaults synchronize];  
}  
}];  
}  
}  
}  
}] resume];  
}  

NSArray 拆分方法如下所示

+ (NSArray *) splitIntoArraysOfBatchSize:(NSArray *)originalArray :(int)batchSize {  
NSMutableArray *arrayOfArrays = [NSMutableArray array];  
for(int j = 0; j < [originalArray count]; j += batchSize) {  
NSArray *subarray = [originalArray subarrayWithRange:NSMakeRange(j, MIN(batchSize, [originalArray count] - j))];  
[arrayOfArrays addObject:subarray];  
}  
return arrayOfArrays;  
} 

----编辑----

我什至尝试将下载分成 1000 条记录的批次,但这也无济于事。

while ( loopCount < numberOfLoops ) {
if([NWTillHelper isDebug] == 1) {
NSLog(@"%s loopCount = %d", __PRETTY_FUNCTION__, loopCount);
NSLog(@"%s startAtRow = %d", __PRETTY_FUNCTION__, startAtRow);
NSLog(@"%s records to fetch = %@", __PRETTY_FUNCTION__, recordsToFetchStr);
}
//[self fetchPricelistAll:(int)[NWTillHelper getPricelist] :0 :recordsToFetch];
[self fetchPricelistAll:(int)[NWTillHelper getPricelist] :startAtRow :batchSizeInt];
startAtRow = startAtRow + batchSizeInt;
loopCount++;
}

我建议拆分 Web 服务响应以位为单位提供数据。您可以从服务器下载位并将其另存为文档文件夹中的文本文件。从文本文件中一个接一个地获取数据并将其保存在核心数据中。保存到核心数据完成后删除文件。

我们可以遵循以下方法

  1. 创建 100/1000 条记录后在上下文中调用 save 方法。
  2. 保存后,我们可以调用重置方法上下文

    [托管对象上下文重置];

最新更新