在两个块中使用变量

时间:2011-01-12 12:13:09

标签: objective-c

我在NSManagedObjectContext中添加了一个方法-dct_asynchronousTaskWithWorkBlock:completionBlock:,它在另一个GCD队列中运行工作块,然后在主线程上运行完成块。该方法执行以下操作:

  1. 创建要在其他队列中使用的第二个托管对象上下文
  2. 使用此新上下文调用工作区
  3. 将该上下文保存并合并到自身
  4. 自行调用完成块
  5. 可以在GitHub上看到此添加内容。

    我的问题是我在工作区中创建了一个新的User托管对象,我想在完成块中引用它。我认为解决方案是创建对象ID的引用,如下所示:

    __block NSManagedObjectID *objectID = nil;
    
    [self.managedObjectContext dct_asynchronousTaskWithWorkBlock:^(NSManagedObjectContext *moc) {
    
        NSManagedObject *user = // create new user.
    
        objectID = [user objectID];
    
    } completionBlock:^(NSManagedObjectContext *moc) {
    
        NSManagedObject *user = [moc objectWithID:objectID];
    
    }];
    

    我也尝试过复制块,在这两种情况下,我在完成块中的objectID上得到了一个EXC_BAD_ACCESS。

    是否可以从完成块引用工作块中的用户objectID?或者我是否需要处理在类别方法中传递引用的方法。

    更新

    Luke对于保留整个块调用是正确的,因为第一个用户位于后台线程中,而第二个用户位于主要位置。

    这是我目前的解决方法:

    __block NSManagedObjectID *objectID = nil;
    
    [self.managedObjectContext dct_asynchronousTaskWithWorkBlock:^(NSManagedObjectContext *moc) {
    
        NSManagedObject *user = // create new user.
    
        objectID = [user objectID];
        [objectID retain];
    
    } completionBlock:^(NSManagedObjectContext *moc) {
    
        NSManagedObject *user = [moc objectWithID:objectID];
        [objectID release];
    
    }];
    

    我现在想知道这看起来是否奇怪。在阅读此代码后,您可能会询问是否存在泄漏。我知道该类别肯定会调用完成块,无论第一个块中发生了什么,但我不知道它是否只是从这段代码看起来很明显。

2 个答案:

答案 0 :(得分:2)

卢克是对的,但是......

为什么要有工作区和完成区?

GCD API最初看起来像:

dispatch_async(q, workBlock, completionBlock);

但事实证明这很愚蠢。 workBlock总是知道它何时完成,为什么不将完成逻辑放入workBlock?除了制作更简单的API之外,它还消除了将状态从工作块传输到完成块的任何空间机制的需要。


dispatch_async(q, ^{
    ... do heavy duty work on background here ...
    dispatch_async(mainQueue, ^{
        ... merge into main queue context here ...
        ... update UI ...
    });
});

答案 1 :(得分:1)

如果您的类别的目的是保持您的工作和完成块清除与第二个MOC的设置和拆卸相关的任何代码,您可以从工作块返回完成块:

[self.managedObjectContext dct_asynchronousTask:^(NSManagedObjectContext *moc) {

    NSManagedObject *backgroundThreadUser = // create new user.
    NSManagedObjectID *objectID = [backgroundThreadUser objectID];

    return ^(NSManagedObjectContext *moc) {
        NSManagedObject *mainThreadUser = [moc objectWithID:objectID];
        // ...
    };
}];