Свойство Objective C против проблем с ivar с Core Data - PullRequest
0 голосов
/ 30 апреля 2011

Я потратил несколько часов, пытаясь выяснить эту проблему, и я думаю, что это сводится к моему фундаментальному пониманию Цели С, хотя это проявилось в работе с Базовыми данными. Я не удивлен - я работаю с Objective C и Cocoa Touch всего два месяца.

Моя ситуация такова, что у меня есть серия моделей, которые все отлично подключены на CD. Мое приложение работает отлично, пока я не попытался расширить его вчера. У меня есть моя основная модель Job в контроллере представления как свойство класса в файле .h. В моем методе viewWillAppear мне нужно искать отношения через другой объект, поэтому я делаю что-то вроде:

/** project as an ivar **/
NSManagedObject *project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do something with divisions --> crash

...

/** project as a property **/
project = [job valueForKey:@"project"];
NSArray *divisions = [[project valueForKey:@"divisions"] allObjects];
//do someting, anything ---> A-OK!

Итак, почему мое приложение вылетает, когда я пытаюсь что-то сделать с результатами [project valueForKey:], если я не делаю проект свойством класса?

EDIT

Похоже, что если просто включить в него условное выражение if(!divisions) (которое должно быть равно нулю при первой загрузке представления), ему не нравятся приведенные выше операторы и выдается EXC_BAD_ACCESS. Однако, если оставить его, мой код работает нормально.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if(!divisions){

        NSManagedObject *project = [[job valueForKey:@"project"] retain];
        NSArray *divs = [[project valueForKey:@"divisions"] allObjects];

        NSSortDescriptor *alphaSort = [NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES];
        divisions = [[divs sortedArrayUsingDescriptors:[NSArray arrayWithObject:alphaSort]] mutableCopy];

    }
    [[self tableView] reloadData];
}

Я согласен с тем, что происходит более серьезная проблема с управлением памятью. Должен ли я вернуться и перечитать некоторые главы книги об Obj-C и пересмотреть мои переменные, чтобы это имело смысл?

Ответы [ 2 ]

0 голосов
/ 01 мая 2011

Я не могу сказать наверняка, основываясь на предоставленном ограниченном коде, но самое простое объяснение сбоя в том, что вы не проверяете, являются ли массивы divs или divisions пустыми, прежде чем выполнять над ними какие-либо операции.

Если отношение Project.divisions пусто, это:

NSArray *divs = [[project valueForKey:@"divisions"] allObjects];

... вернет пустой массив.Любая попытка обратиться к любому элементу массива, например, [divs objectAtIndex:0], приведет к ошибке.

Кроме того, divisions представляется iVar объекта контроллера, но вы не используете ни предпочтительный self.divisionsсправочная форма или [divisions retain] при назначении ей массива 'divs'.Поскольку массив divs будет возвращен автоматически освобожденным, он будет очищен при следующем сливе пула, а массив в divisions исчезнет, ​​даже если он не будет пустым.

Просто измените divisions на self.divisions, чтобы исправить.

0 голосов
/ 01 мая 2011

Помимо путаницы с иваром, у вашего кода есть еще две проблемы. При доступе к атрибуту в NSManagedObject вы должны использовать primitiveValueForKey: как в

[job willAccessValueForKey:@"project"];
NSManagedObject *project = [job primitiveValueForKey:@"project"];
[job didAccessValueForKey:@"project"];

Каждый раз, когда вы получаете или устанавливаете свойство существующего управляемого объекта, вы всегда должны предшествовать вызову willAccessValueForKey: и закрывать с didAccessValueForKey: так, чтобы модель и хранилище оставались синхронизированными.

Еще лучше было бы

[job willAccessValueForKey:@"project"];
NSManagedObject *project = [job primitiveProject];
[job didAccessValueForKey:@"project"];

но, к сожалению, отладчик Xcode этого не делает, и вам приходится мириться с этими надоедливыми желтыми предупреждениями.

Кроме того, отношение NSManagedObject возвращает NSSet, а не массив:

[project willAccessValueForKey:@"divisions"];
NSSet *divisions = [project primitiveValueForKey:@"divisions"];
[project didAccessValueForKey:@"divisions"];

Подробнее в Apple Руководство по реализации объекта модели

Наконец, если вы делаете все это для заполнения таблицы, вам гораздо лучше создать экземпляр NSFetchedResultsController, который оптимизирован именно для этой задачи.

...