如何加快连续提取并保存对核心数据的请求

时间:2015-05-21 07:15:45

标签: ios objective-c xcode core-data

我遇到的情况是我必须处理连续获取和保存请求。当我必须处理的数据量增加时,我的应用程序正在冻结。我的节省会立即更新到NSFetchedResultsController的桌面视图。我试图通过使用示例代码来隔离我的问题,我在下面放了一些代码。冻结问题在这个地区。我将至少保存3000条记录。有人请帮我解决我的UI冻结问题。

这是运行项目的探查器日志:https://www.dropbox.com/s/tf1eiz3c5vnr0hq/Instruments10.trace.zip?dl=0

- (void)coreDataTest {

// Create NSManagedObjectModel and NSPersistentStoreCoordinator

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"store.sqlite"];

// remove old store if exists

NSFileManager *fileManager = [NSFileManager defaultManager];

if ([fileManager fileExistsAtPath:[storeURL path]])

    [fileManager removeItemAtURL:storeURL error:nil];

NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

NSPersistentStoreCoordinator *storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

[storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType

                               configuration:nil

                                         URL:storeURL

                                     options:nil

                                       error:nil];

NSManagedObjectContext* masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[masterContext setPersistentStoreCoordinator:storeCoordinator];

// create the parent NSManagedObjectContext with the concurrency type to NSMainQueueConcurrencyType

_parentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

[_parentContext setParentContext:masterContext];

// creat the child one with concurrency type NSPrivateQueueConcurrenyType

_childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[_childContext setParentContext:_parentContext];

// create a NSEntityDescription for the only entity in this CoreData model: Test

NSEntityDescription *testDescription = [NSEntityDescription entityForName:@"Test"

                                                   inManagedObjectContext:_parentContext];

// perform a heavy write block on the child context

__block BOOL done = NO;

[_childContext performBlock:^{

    for (int i = 0; i < 3000; i++){

        Test *test = [[Test alloc] initWithEntity:testDescription

                   insertIntoManagedObjectContext:_childContext];

        test.test = [NSString stringWithFormat:@"Test %d", i];

        NSLog(@"Create test %d", i);

        [_childContext save:nil];

    done = YES;

    dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"Done write test: Saving parent");

        [_parentContext save:nil];

        NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Test"];

        NSLog(@"Done: %d objects written", [[_parentContext executeFetchRequest:fr error:nil] count]);

        [masterContext performBlock:^{

            [masterContext save:nil];

        // execute a fetch request on the parent to see the results

        }];

    });

    }

}];

// execute a read request after 1 second

double delayInSeconds = 1.0;

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

    NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Test"];

    [_parentContext performBlockAndWait:^{

        NSLog(@"In between read: read %d objects", [[_parentContext executeFetchRequest:fr error:nil] count]);

    }];

});   
}

2 个答案:

答案 0 :(得分:0)

尝试以下提高速度的步骤

1 - 使用NSFethedResultControler,它将帮助您在每次保存后自动重新加载数据,因为每次保存后都会调用其委托

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{
     [self fetchCoreDataArrayAfterSave];
}

2 - 尝试一次分批保存(100)

3 - NSMangedObjectContext的用户insertObject方法而不是save,save将在插入100个批处理后立即使用。

for (int i = 0; i <first 100; i++){

    Test *test = [[Test alloc] initWithEntity:testDescription

               insertIntoManagedObjectContext:_childContext];

    test.test = [NSString stringWithFormat:@"Test %d", i];


    [_childContext insertObject:test]
 };

 [_childContext save:nil];

4 - 在后台完成所有这些

5 - 使用批次来获取数据。

如果您无法理解任何一点,请随时提出。

答案 1 :(得分:0)

对于执行快速插入而不阻塞主线程使用上面的代码

//在Appdelegate中创建父上下文

- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
    return _managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
     [_managedObjectContext setUndoManager:nil];
}
return _managedObjectContext;
}

//在Appdelegate中创建子上下文

- (NSManagedObjectContext *)childManagedObjectContext
{
if (_childManagedObjectContext != nil) {
    return _childManagedObjectContext;
}

_childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[_childManagedObjectContext setParentContext:_managedObjectContext];


return _childManagedObjectContext;
}

//现在执行保存操作

[UIAppDelegate.childManagedObjectContext performBlock:^{

        //Fill Ur Daatbse (Insert)
       for (int i=0; i<count; i++) {
             [UIAppDelegate.childManagedObjectContext save:nil];
        }


        dispatch_sync(dispatch_get_main_queue(), ^{

            [UIAppDelegate.managedObjectContext save:nil];
            [UIAppDelegate hideProgressBar];


        });

    }];