MagicalRecord和dispatch_group

时间:2013-08-21 09:24:49

标签: ios grand-central-dispatch magicalrecord

我正在使用MagicalRecord,在我的一个视图控制器中,数据源是来自数据库的数据。由于喂养过程包括多个步骤,我尝试使用GCD来加速整个过程。 一般过程看起来像这样。

在globalSummary中获取访问属性后要完成的工作。 问题是应用程序挂起在dispatch_group_wait。我试图在步骤中添加工作并且它在开始时工作但是当我添加更多工作时,如果我逐步完成代码但是如果我让它运行则不起作用。

这种方法有问题,还是以某种方式与MagicalRecord冲突?

- (NSArray *)dataSource
{
    if (_dataSource == nil) {

    _dataSource = [NSMutableArray array];
    NSManagedObjectContext *privateContext = [NSManagedObjectContext contextWithStoreCoordinator:[NSPersistentStoreCoordinator defaultStoreCoordinator]];

    GlobalSummary *globalSummary = [GlobalSummary insertInManagedObjectContext:privateContext]; // holds a bunch of fetched properties

    dispatch_queue_t queue = dispatch_queue_create("de.berndrabe.dataSource", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t outerGroup = dispatch_group_create();

    __block SectionInfo *siPilotAircraft = nil;
    if ([PilotAircraft countOfEntities]) {
        dispatch_group_async(outerGroup, queue, ^{
            NSArray *frPilotAircraft = [PilotAircraft findAll];
            // do some processing an set SectionInfo variable
        });
    }

    __block SectionInfo *siMedicals = nil;

    if ([PilotMedical countOfEntities]) {
        dispatch_group_async(outerGroup, queue, ^{
            NSArray *frPilotMedical = [PilotMedical findAll];
        });
    }

    // more working packets following the same patter

    dispatch_group_wait(outerGroup, DISPATCH_TIME_FOREVER);

    if (siPilotAircraft.countOfRows) {
        [_dataSource addObject:siPilotAircraft];
    }
    if (siMedicals.countOfRows) {
        [_dataSource addObject:siMedicals];
    }
}

return _dataSource;
}

编辑:   使用[Entity findAllInContext:privateContext]可以获取我需要的记录,但现在我仍然在访问一个实体中的错误关系时遇到困难:(

2 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。 在这里(简而言之)我试图完成的任务。

任务 构建一个NSMutableArray,它将作为UITableView的dataSource对象 每个条目包括核心数据获取和处理操作 并行化工作并在完成时添加结果,确保对NSMutableArray的访问受到监管 在完成时开始使用dataSource对象

问题 dataSource对象中的条目数可以变化

这对我有用。 'NSMutableArray'上的类别是确保访问序列化的便捷方法。 通过该实现,您可以尽可能地并行化工作,并且可以节省 写

[self prepareDataSource]; [self.tableView reloadData];

不用担心某些工作仍在进行中。

dispatch_queue_t queue = dispatch_queue_create("com.yourdomain.serializedAccess", DISPATCH_QUEUE_CONCURRENT);

- (void)prepareDataSource
{
    [self.dataSource removeAllObjects];

    dispatch_group_t group = dispatch_group_create();

    [self prepareWorkEntry1FromManagedObjectContext:self.privateContext forDataSource:self.dataSource group:group];
    [self prepareWorkEntry2FromManagedObjectContext:self.privateContext forDataSource:self.dataSource group:group];
    [self prepareWorkEntry3FromManagedObjectContext:self.privateContext forDataSource:self.dataSource group:group];

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

- (void)prepareWorkEntry1FromManagedObjectContext:(NSManagedObjectContext *)context forDataSource:(NSMutableArray *)array group:(dispatch_group_t)group
{
    __weak typeof(self) weakSelf = self;

    dispatch_group_enter(group);
    [context performBlock:^{
    Object *object = nil;
        createObject(object);

    if (object) {
           [array serializedAddObject:object withQueue:weakSelf.queue group:group];
        }
        else {
          dispatch_group_leave(group);
        }
    }];
}


@implementation NSMutableArray (ResourceProtection)

- (void)serializedAddObject:(id)object withQueue:(dispatch_queue_t)queue group:(dispatch_group_t)group
{
    if (group == NULL) {
        dispatch_barrier_async(queue, ^{
            [self addObject:object];
        });
    } else {
        dispatch_barrier_async(queue, ^{
            [self addObject:object];
            dispatch_group_leave(group);
        });
    }
}

@end

编辑: 就ResourceProtection类别而言,您必须确保

  1. 在dispatch_group_leave
  2. 之前调用dispatch_group_enter
  3. dispatch_group_enter和dispatch_group_leave是平衡的
  4. 这是一个观察到的可变对象的同步编写器方案。

答案 1 :(得分:0)

我想提出另一种使用辅助库的方法,它使异步任务更容易实现:它使用“Promises”作为指示异步任务完成(或失败)的手段。

基本上,异步任务(本例中的方法)不是完成块,而是如下所示:

- (RXPromise*) doSomethingAsync;

最终结果分别是失败,可以通过处理程序获得,这些处理程序将被“注册”,如下所示:

- (void) foo 
{
   RXPromise* promise = [self doSomethingAsync];
   promise.then( <completion handler block>, <error handler block> );
}

或更短,并且处理程序占位符填充了实际代码:

- (void) foo 
{
    [self doSomethingAsync]
    .then(^id(id result) 
    {
        // result is the eventual result of the asynchronous task
        return nil; // return the result of the handler

    }, id(NSError*error)
    {
         NSLog(@"ERROR: %@, error"); // the task failed with error
         return nil;
    });
}

注意:处理程序本身在专用线程上执行(实际上是并发调度队列)。 为了在处理程序内同步共享访问,可以显式指定将执行处理程序的调度队列:

- (void) foo 
{
    [self doSomethingAsync]
    .thenOn(dispatch_get_main_queue()), ^id(id result) 
    {
        // Here, we are executing on the main thread
        // result is the eventual result of the asynchronous task
        return nil; // return the result of the handler

    }, id(NSError*error)
    {
        // Here, we are executing on the main thread
         NSLog(@"ERROR: %@, error"); // the task failed with error
         return nil;
    });
}

请注意,[self doSomethingAsync]中执行的异步任务可以在其自己的专用线程(或队列)上执行。

可以轻松完成多个异步任务的“继续”:

task1()
.then(^id(id result1{
    return task2(result1);
}, nil)
.then(^id(id result2) {
    return task3(result2);
}, nil)
.then(nil, ^id(NSError*error)
    NSLog(@"Something went wrong in task1 or task2 or task3: %@", error);
    return nil;
);

在简短介绍之后,您可以按如下方式解决问题:

定义返回RXPromise的异步任务:
- (RXPromise*) prepareWorkEntry1FromManagedObjectContext:(NSManagedObjectContext *)context;
- (RXPromise*) prepareWorkEntry2FromManagedObjectContext:(NSManagedObjectContext *)context;
- (RXPromise*) prepareWorkEntry3FromManagedObjectContext:(NSManagedObjectContext *)context;


- (RXPromise*) prepareWorkEntry1FromManagedObjectContext:(NSManagedObjectContext *)context
{
    RXPromise* promise = [RXPromise new];
    [context performBlock:^{
        Object *object = nil;
        createObject(object);

        if (object) {
           // success
           [promise fulfillWithValue:object];
        }
        else {
           // failure 
           [promise rejectWithReason:@"object creation failed"];
        }
    }];

    return promise;
}

同样,执行其他任务。

在处理程序中组合结果:
- (void) foo 
{
    [self prepareWorkEntry1FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 1";
    }, nil);

    [self prepareWorkEntry2FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 2";
    }, nil);

    [self prepareWorkEntry3FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 3";
    }, nil);

}

请注意,dataSourceArray将在专用sync_queue中访问。这应该是一个串行调度队列。

另请注意,方法foo实际上是异步的。

在完成许多异步任务之前,还有可能“异步等待”:

- (void) foo {

    NSArray* promises = @[

    [self prepareWorkEntry1FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 1";
    }, nil),

    [self prepareWorkEntry2FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 2";
    }, nil),

    [self prepareWorkEntry3FromManagedObjectContext:moc]
    .thenOn(self.sync_queue, (^id(id object)) {
        [self.dataSourceArray addObject:object];
        return @"Finished 3";
    }, nil)

    ];

    [RXPromise all:promises]
    .then(^id(id arrayOfPromises){
        // all tasks *and its handlers* finished.
        ...
        return nil;
    }, nil);
}

我是这个图书馆的作者,你可以在这里找到:RXPromise