Удаление / удаление записей в Core Data очень очень медленно

Я делаю последние штрихи в приложении и испытываю трудности с массовым удалением записей. При нажатии кнопки набор прибл. 3500 записей должны быть добавлены в базу данных. Это не проблема, и занимает ок. 3-4 секунды.

Но иногда (не часто, но опция должна быть там) все эти записи должны быть удалены. Я только что запустил эту операцию, и это заняло 20 минут. Что здесь может быть не так? Существует только одна зависимость, все записи являются дочерними для определенной коллекции.

Я добавляю все элементы в набор, удаляю их из Коллекции и затем удаляю один за другим. Каждые 5% я обновляю диалог, и когда все сделано, я фиксирую изменения. Но удаление элементов просто занимает много времени (как я вижу, прогресс прогресс очень медленно)

- (void) deleteList:(DOCollection *) collection {

    // For the progress dialogue
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:@"Clearing vocabulary list!" forKey:@"message"];
    float totalItems = [collection.items count];
    float progress = 0;
    float nextProgressRefresh = 0.05;         

    NSMutableSet* itemsSet = [NSMutableSet set];
    for (DOItem* item in collection.items) {
        [itemsSet addObject:(NSNumber*)[NSNumber numberWithInt:[item.itemId intValue]]];
    }

    // Remove all of them from the collection
    [managedObjectContext performBlockAndWait:^{
        [collection setItems:[NSSet set]];
    }];    

    for (NSNumber* itemId in itemsSet) {
        DOItem* item = [itemController findItem:[itemId intValue]];
        if (item != nil) {
           [[self itemController] removeItem:item];
        }

        progress++;
        if((nextProgressRefresh < (progress / totalItems))){  
            NSString* sProgress = [NSString stringWithFormat:@"%f", (progress / totalItems) * 0.85];
            //[dict setValue:@"Saving the database...!" forKey:@"message"];
            [dict setValue:sProgress forKey:@"progress"];
            [[NSNotificationCenter defaultCenter] postNotificationName:kUpdatePleaseWaitDialogue object:dict]; 
            nextProgressRefresh = nextProgressRefresh + 0.05;
        }        
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [managedObjectContext performBlockAndWait:^{
            [[self collectionController] commitChanges];
        }];
        [[NSNotificationCenter defaultCenter] postNotificationName:kSavingDataComplete object:nil]; 
    });  

    //NSLog(@"Wait 2!");
    [NSThread sleepForTimeInterval:1];    

}

в DOItemController:

- (void) removeItem: (NSManagedObject*) item {
    [[self managedObjectContext] deleteObject:item];
}

1 ответ

Решение

Не уверен, как вы спроектировали свои модели данных. Но я бы настроил его на каскадное удаление ваших объектов. Если объекты DOItem уникальны для коллекции DOCollection, вы можете установить правило удаления каскадным. Это автоматически удалит связанный DOItem, а также удалит его из объекта набора элементов DOCollection.

Чтобы удалить объекты DOItem из коллекции DOCollection, проверьте файл DOCollection.h, у вас должен быть метод, аналогичный

-(void)removeDOItemObjects:(NSSet *)value

в противном случае они могут по-прежнему динамически генерироваться Core Data для вас. В вашем заголовочном файле у вас должно быть что-то вроде:

@property(nonatomic,retain) DOItem *items

тогда в вашем файле реализации у вас должно быть что-то вроде:

@synthesize items

Соответствующие методы, которые должны быть сгенерированы для них автоматически:

-(void)addItemsObject:(DOItem*)value
-(void)addItems:(NSSet *)values
-(void)removeItemsObject:(DOItem *)value
-(void)removeItems:(DOItem *)values
-(NSSet *)items

См. "Пользовательские методы доступа к многим отношениям" здесь для получения дополнительной информации.

Этот метод предназначен для вас, когда вы создаете модель данных и связанные файлы реализации и должен быть сильно оптимизирован Core Data. Тогда все, что вам нужно сделать, чтобы удалить объекты, это что-то вроде:

- (void) deleteList:(DOCollection *) collection {

    // Remove all of them from the collection
    [managedObjectContext performBlockAndWait:^{
        // Updated 01/10/2012
        [collection removeItems:collection.items];
        NSError *error = nil;
        if (![managedObjectContext save:&error]) { 
           NSLog(@"Core Data: Error saving context."); }
       };
    }];

}

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

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

Удачи!

Другие вопросы по тегам