核心数据 - 内存使用情况:我的应用程序崩溃了

时间:2011-05-13 12:25:39

标签: iphone ipad core-data memory-management loops

我的问题是关于核心数据和内存使用情况。我之前使用过核心数据,但这次数据量更高,这让我意识到还有更多要知道的东西。我已经看到有其他几个类似的帖子,我从他们那里得到了有趣的信息,但在应用它后我的应用程序仍然崩溃。我一直在处理这个问题一个星期了。有人请帮忙。

基本上我分别有三个64,15和17次迭代的类似循环。它们在模拟器上工作正常。在几台iPad上测试后,它们会收到内存警告,并且在同一次迭代中崩溃(第一个循环的第34个)。在iPad 2上测试它将在第二个循环的第14位崩溃。仪器显示实时和整体的内存使用量约为1.5 MB。泄漏几KB。

循环执行以下(代码如下)

  • 执行核心数据提取
  • 对于每条记录,将一个参数存储为行属性属性(String)
  • 调用一个过程,该过程接受该参数并返回数据(大约数百KB)
  • 将这些数据存储在同一行的另一个属性属性(Transformable)中

非常常见的任务不是吗?

现在,由于我遇到了内存问题,我尝试使用我所知道的所有已知(我)工具,它们是:

  • 尽快释放拥有的对象
  • 创建自动释放池并尽快排空它们,而不是拥有对象
  • 保存上下文asap
  • 将对象转换为错误

应用所有这些技术后,我得到了一个令人兴奋的结果:应用程序在与之前完全相同的位置崩溃。

这是代码。

- (void) myMainProcedure {
    [self performLoop1];
    [self performLoop2];  // Similar to loop1
    [self performLoop3];  // Similar to loop1
}
- (void) performLoop1 {
    NSError * error = nil;
    NSAutoreleasePool * myOuterPool;
    NSAutoreleasePool * myInnerPool;

    NSManagedObjectContext * applicationContext = [[[UIApplication sharedApplication] delegate] managedObjectContext];
    [applicationContext setUndoManager:nil];


    NSEntityDescription * myEntityDescription = [NSEntityDescription entityForName:@"EntityName"
                                               inManagedObjectContext:applicationContext];
    NSFetchRequest * myFetchRequest = [[NSFetchRequest alloc] init];
    [myFetchRequest setEntity:myEntityDescription];

    NSString * column = @"columnName";
    NSPredicate * aWhereClause = [NSPredicate predicateWithFormat:
                                  @"(%K = %@)", column, [NSNumber numberWithInt:0]];
    [myFetchRequest setPredicate: aWhereClause];

    myOuterPool = [[NSAutoreleasePool alloc] init];
    NSArray * myRowsArray = [applicationContext executeFetchRequest:myFetchRequest                                                                     
                                                              error:&error];
    NSMutableArray * myRowsMutableArray = [[NSMutableArray alloc] initWithCapacity:0];
    [myRowsMutableArray addObjectsFromArray: myRowsArray];
    [myOuterPool drain];
    [myFetchRequest release];

    EntityName * myEntityRow;
    int totalNumberOfRows = [myRowsMutableArray count];

    myOuterPool = [[NSAutoreleasePool alloc] init];
    for (int i = 0; i < totalNumberOfRows; i++) {

            myInnerPool = [[NSAutoreleasePool alloc] init];
            myEntityRow = [myRowsMutableArray objectAtIndex:0];
            NSString * storedSmallAttribute = myEntityRow.smallAttribute;
            UIImageView * largeData = [self myMethodUsingParameter: smallAttribute];
            myEntityRow.largeAttribute = largeData;
            [myRowsMutableArray removeObjectAtIndex:0];

            [applicationContext save:&error];
            [applicationContext refreshObject:myEntityRow mergeChanges:NO];
            [myInnerPool drain];
            [largeData release];
    }
    [myOuterPool drain];
    [myRowsMutableArray release];
}

- (UIImageView *)  myMethodUsingParameter : (NSString *) link { 
    UIImageView * toBeReturned = nil;
    NSURL *pdfURL = [NSURL fileURLWithPath:link];
    CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
    CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
    CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
    UIGraphicsBeginImageContext(pageRect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
    CGContextFillRect(context,pageRect);
    CGContextSaveGState(context);
    CGContextTranslateCTM(context, 0.0, pageRect.size.height);
    CGContextScaleCTM(context, 1, - 1);
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 
    CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
    CGContextDrawPDFPage(context, page);
    CGContextRestoreGState(context);
    UIImage *imageToBeReturned = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CFRelease(pdf);  
    toBeReturned = [[UIImageView alloc] initWithImage:imageToBeReturned];
    UIGraphicsEndImageContext();
    return toBeReturned;
}
  • 请注意

    • 可变阵列是作为(显然无用的)策略引入的 让物品尽快释放
    • 池已添加为同一策略的一部分
    • 关于插值质量的陈述是唯一需要改进的 情况(例如,移动崩溃 一点点前进)
    • 在周期范围内保留托管对象的计数范围为6到10 (?)我知道rc不是很有价值 信息,但仍然,我做了一个测试 我发现我可以发送 要管理的多个发布消息 强制应用程序之前的对象 为此崩溃。但重点是 我不应该发布一个 对象我不拥有,是吗? ....
    • 设置请求的实体也有一些 与...的双向关系 其他实体,但仍然是这样 相关?

谢谢。

1 个答案:

答案 0 :(得分:0)

我认为你应该重新审视一下你的问题。 处理核心数据的方法有很多,比您的方法简单得多。 为您的Core Data实体创建类文件可能对您有所帮助。 此外,在保存文件时,应认真评估每个对象的必要性以及是否可以采用更好的方式。 在你的情况下,我会提出两个建议:


对于每个PDF网址,

  • a。分配唯一标识符。
  • b。将此唯一标识符保存在您的 核心数据存储。
  • c。将网址添加到队列中 创造的背景过程 你的PDF(后台流程将是 允许用户继续工作 正在生成PDF。你
    可以更新您的代表 进度或创建临时图像 当PDF为
    时替换 创建。)
  • d。在您的应用中保存图像 目录(或照片库)使用 唯一标识符作为名称。
  • e。需要时,从中加载图像 磁盘变成UIImageView或
    适当的。

对于每个PDF网址,

  • a。绘制PDF。
  • b。获取UIImage表示
  • c。转换为PNG NSData (UIImagePNGRepresentation(图像))
  • 在CoreData中保存NSData。
  • e.Load NSData并转换为UIImage 需要的时候。