Производительность: отношения основных данных становятся ошибочными после назначения

У меня есть модель Core Data, представляющая телегид iOS 4+ с тремя классами:

  • Channel (BBC 1)
  • Program (Top Gear)
  • Broadcast (Top Gear на BBC 1 в понедельник в 8 вечера)

У меня около 40 каналов, 8000 программ и 6000 трансляций, и я хотел бы настроить процесс импорта так, чтобы он не занимал минуты до запуска.

Импортировать каналы и программы легко, потому что это независимые объекты. Однако широковещательная передача имеет отношение к каналу и к программе (от 1 до многих), и оба канала и программы имеют обратные отношения с широковещательными передачами (много-к-1). Чтобы ускорить работу, у меня есть словарь в памяти каналов и программ, у которых есть только их идентификатор веб-службы: я создаю трансляцию и просматриваю оба словаря, чтобы получить соответствующий канал и программу без обратного перехода к базе данных.

Но когда я назначаю программу или канал для широковещательной передачи, доступ к обратным связям канала и программы вызывает сразу две ошибки обоих объектов, что вызывает значительное замедление (запросы 6000 * 2) и последующее давление памяти, как показано в разделе «Основные ошибки данных» Отчет по инструментам. Я попробовал предварительную выборку отношений broadcasts на обоих каналах и программах, но связь все равно становится ошибочной.

У вас есть идеи, почему обратные отношения доступны и виноваты их родители? Как избежать чтения из базы данных при сохранении отношений?

UPDATE: пример кода, мой метод назначения / обновления для экземпляра Broadcast . Переменная dictionary поступает из веб-службы, а channels и programs содержат каналы ошибок и объекты программ, индексированные идентификатором веб-службы. Неисправность происходит в программе self.program = program и self.channel = channel .

 - (BOOL)assignWithDictionary:(NSDictionary *)dictionary channels:(NSDictionary *)channels programs:(NSDictionary *)programs { // Add channel relationship NSNumber *channelIdentifier = [dictionary objectForKey:@"channel_id"]; if (self.channel == nil || ![self.channel.identifier isEqualToNumber:channelIdentifier]) { Channel *channel = [channels objectForKey:channelIdentifier]; if (channel == nil) { NSLog(@"Broadcast %@ has invalid channel: %@", identifier, channelIdentifier); return NO; } self.channel = channel; } // Same to add a program relationship // ... } 

И мой запрос получения для получения каналов или списка программ:

 - (NSDictionary *)itemsForEntity:(NSEntityDescription *)entity { NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; NSError *error = nil; NSArray *itemsArray = nil; request.entity = entity; request.relationshipKeyPathsForPrefetching = [NSArray arrayWithObject:@"broadcasts", nil]; request.propertiesToFetch = [NSArray arrayWithObjects:@"identifier", @"version", nil]; itemsArray = [self.context executeFetchRequest:request error:&error]; NSAssert1(error == nil, @"Could not fetch the items from the database: %@", error); { NSMutableDictionary *items = [NSMutableDictionary dictionaryWithCapacity:itemsArray.count]; for (NSManagedObject *item in itemsArray) { [items setObject:item forKey:[item valueForKey:@"identifier"]]; } return [NSDictionary dictionaryWithDictionary:items]; } } 

    Не совсем уверен, что вы пытаетесь сделать здесь, но …

    Во-первых, вы не можете изменять свойства, используя только ошибки. Ошибки – это просто заполнители, позволяющие вам измерять / подсчитывать граф объектов и строить отношения. Если вы на самом деле изменяете отношения, это приведет к сбою, вызвав загрузку связанных объектов.

    Если вы пытаетесь установить отношения между конкретными объектами Channel , Program и Broadcast используя только ошибки, это не сработает.

    Ваши itemsForEntity: метод, который я не понимаю. Он будет извлекать каждый существующий управляемый объект переданного объекта и затем возвратит эти объекты в словаре. Это вызовет огромные издержки памяти, особенно в случае объектов Program из которых 8000.

    Вы не можете использовать propertiesToFetch если вы не установите возврат извлечения в словарь, которого нет. Вы не можете использовать тип возвращаемого словаря в любом случае, если вам нужно установить отношения. Вы используете оба эти параметра, когда все, что вам нужно, это данные, хранящиеся в определенных атрибутах. Это не инструмент для манипулирования отношениями объекта-графика.

    Настройка relationshipKeyPathsForPrefetching только ускоряет работу, если вы знаете, что будете получать доступ к существующим отношениям. Это не помогает, когда вы устанавливаете отношения в первую очередь, например, если в отношениях broadcasts нет существующих объектов или вы добавляете или удаляете объекты Broadcast , предварительная выборка broadcasts ключевым словам не делает ничего для вас.

    Я не уверен, что я правильно понимаю вашу модель данных, но я думаю, что вы делаете это неправильно. Мне кажется, что вы пытаетесь использовать identifier как первичный ключ в базе данных SQL, и это контрпродуктивно. В Core Data отношения связаны с объектами вместе, а не с общим атрибутом и значением.

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

    Давайте будем гением компьютера.