1

我正在使用 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]让获取我需要的记录,但现在我在访问一个实体中的错误关系时仍然卡住了:(

4

2 回答 2

0

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

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

- (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

于 2013-08-26T18:31:35.453 回答
0

我找到了解决我的问题的方法。这里再次(简而言之)我试图完成的事情。

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

问题 dataSource 对象中的条目数可能会有所不同

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

[自我准备数据源];[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_enter 在 dispatch_group_leave 之前被调用
  2. dispatch_group_enter 和 dispatch_group_leave 是平衡的

这是一个可观察的、同步的可变对象写入器方案。

于 2013-08-26T16:14:30.000 回答