Основные данные - использование памяти: мое приложение падает - PullRequest
4 голосов
/ 13 мая 2011

Мой вопрос об основных данных и использовании памяти. Я использовал основные данные раньше, но на этот раз объем данных был выше, и это заставило меня понять, что нужно знать намного больше. Я видел, что есть несколько других подобных постов, и я получил от них интересную информацию, но после ее применения мои приложения по-прежнему зависают. Я занимаюсь этим вопросом уже неделю. Кто-нибудь, пожалуйста, помогите.

По сути, у меня есть три последовательных одинаковых цикла по 64, 15 и 17 итераций соответственно. Они отлично работают на симуляторе. Протестировано на нескольких iPad, они получают предупреждения памяти и они терпят крах на той же итерации (номер 34 первого цикла). Протестировано на iPad 2, оно рухнет под номером 14 второго цикла. Инструменты показывают использование памяти около 1,5 МБ как в реальном времени, так и в целом. Есть утечки на несколько килобайт.

Циклы выполняют следующее (код ниже)

  • Выполнить выборку с основными данными
  • Для каждой записи взять параметр, хранящийся в качестве атрибута свойства строки (String)
  • Вызов процедуры, которая принимает этот параметр и возвращает данные (около сотни КБ).
  • Сохранить эти данные в другом атрибуте свойства (Transformable) той же строки

Довольно распространенная задача, не правда ли?

Теперь, так как у меня возникли проблемы с памятью, я попытался использовать все известные мне инструменты, а именно:

  • освободить принадлежащие объекты как можно скорее
  • создавать пулы авто-релиза и сливать их как можно скорее для не принадлежащих объектов
  • сохранить контекст как можно скорее
  • превратить объекты в недостатки как можно скорее

После применения всех этих приемов я получил потрясающий результат: приложение вылетает в тот же момент, что и раньше.

Вот это код.

- (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 голосов
/ 13 мая 2011

Я думаю, вы должны по-новому взглянуть на свою проблему. Есть много способов справиться с Базовыми данными, которые намного проще, чем ваш подход. Создание файлов классов для ваших сущностей Core Data может вам помочь. Кроме того, когда вы сохраняете свои файлы, вы должны серьезно оценить необходимость каждого объекта и то, можно ли это сделать лучше. В вашем случае я бы предложил два предложения:


Для каждого URL PDF,

  • a. Назначьте уникальный идентификатор.
  • б.Сохраните этот уникальный идентификатор в своем основное хранилище данных.
  • c. Добавить URL в очередь для фоновый процесс, который создает
    Ваш PDF (фоновый процесс будет
    позволить пользователю продолжать работать в то время как PDF-файлы создаются. Вы
    может обновить вашего делегата на
    прогресс или создать временное изображение это заменяется, когда PDF
    создан.)
  • d. Сохраните изображение в вашем приложении. каталог (или библиотека фотографий) с помощью уникальный идентификатор как имя.
  • д. При необходимости загрузите изображение из диск в UIImageView или
    что угодно.

Для каждого URL PDF,

  • a. Нарисуйте PDF.
  • b.Get UIImage представление
  • c.Конвертировать в PNG NSData (UIImagePNGRepresentation (изображение))
  • d.Сохранить NSData в CoreData.
  • e.Load NSData и конвертировать в UIImage когда нужно.
...