阻止当前线程,直到部分代码在iOS主线程上运行

时间:2014-09-20 15:00:07

标签: ios objective-c multithreading

我有一个用例,我将数据写入ios中的本地couchebase数据库。这里它不支持写操作的并发访问。所以我想在主线程上运行CRUD操作,并在对辅助线程上的数据运行一些算法后返回结果。当主线程接管控制并执行代码时,当前运行的线程不等待主线程完成其操作。如何将结果从主线程切换到其他线程。

前:

+(BOOL)createDocument:(NSDictionary*)data withId:(NSString*)docId {
    __block CBLDocument* doc = nil;
    //        NSLog(@"%d count ", [[self database] documentCount]);
    dispatch_async(dispatch_get_main_queue(), ^{
        if(docId.length > 0) {
            doc = [[self getDatabase] documentWithID:docId];
        } else {
            doc = [[self getDatabase] createDocument];
        }
    });

    //I want current thread to wait till main thread completes its execution
    if(doc){
        return YES;
    }else{
        return NO;
    }
}

2 个答案:

答案 0 :(得分:2)

如果你知道这个方法没有从主队列中调用,你可以使用dispatch_sync

+(BOOL)createDocument:(NSDictionary*)data withId:(NSString*)docId {
    __block CBLDocument* doc = nil;

    dispatch_sync(dispatch_get_main_queue(), ^{
        if(docId.length > 0) {
            doc = [[self getDatabase] documentWithID:docId];
        } else {
            doc = [[self getDatabase] createDocument];
        }
    });

    //I want current thread to wait till main thread completes its execution
    if(doc){
        return YES;
    }else{
        return NO;
    }
}

更通用的方法是为数据库交互创建专用的自定义调度队列。然后,任何想要与数据库交互的线程(主线程或任何后台线程)都会对该专用队列执行dispatch_sync

这提供了一个更清晰的实现,使功能意图更加明确,并确保从后台线程启动的数据库交互不会阻塞主线程(当然,除非主线程正好启动与此数据库的数据库交互同时排队)。这种专用队列方法符合“每个子系统一个队列”的精神。 WWDC 2012 video, Asynchronous Design Patterns with Blocks, GCD, and XPC中讨论的设计模式(它是视频后半部分讨论的第五种设计模式)。

答案 1 :(得分:0)

您可以从主线程对您的“当前主题”进行另一次dispatch_async调用。因此,您将使用另一个功能块并将if(doc)内容放入其中。这就是使用GCD API处理线程之间的链接的方式。

因此,代码的问题是,createDocument在调度到另一个线程后返回。相反,您应该更改createDocument以获取功能块参数。

+(BOOL)createDocument:(NSDictionary*)data 
  withId:(NSString*)docId 
  onComplete:(void (^)(CBLDocument*))onComplete;

按照以下方式更改dispatch_async来电:

dispatch_async(dispatch_get_main_queue(), ^{
    if(docId.length > 0) {
        doc = [[self getDatabase] documentWithID:docId];
    } else {
        doc = [[self getDatabase] createDocument];
    }
    dispatch_async(yourCurrentThread, ^{
        onComplete(doc);
    });
});

但是,如果你真的想要阻止你当前的线程,你应该使用dispatch_sync而不是dispatch_async

dispatch_sync(dispatch_get_main_queue(), ^{
    ...
});

return doc != nil;

对不起,如果有任何语法错误,我还没有测试过。

相关问题