将异步调用包装到同步阻塞线程中?

val*_*eru 10 multithreading asynchronous objective-c synchronous ios

我正在编写一个iOS模块,它当前以异步方式发送电子邮件(使用委托).它的使用SKPSMTPMessage效果很好.我的问题是客户希望代码完全阻止线程,直到电子邮件发送(或无法发送).因此,他们基本上要求同步解决方案,当前它将尝试发送电子邮件,然后在发送电子邮件之前从该代码块返回.

因此,我没有尝试以SKPSMTPMessage同步的方式重写代码(似乎没有任何同步选项),我希望找到一些方法将异步代码块包装在自己的线程中,并可能使主线程等待它完全结束(代表和所有).

我尝试了一些使用NSOperations的不同方法,NSThread但也许我没有做正确的事情,因为每次我试图阻止主线程时,异步委托调用仍然似乎永远不会完成(他们回到主线程还是什么东西) ?).

任何信息甚至其他想法赞赏.

PS~我意识到这有点倒退了.在大多数情况下,异步似乎是要走的路,但这是一个特例,客户有理由想要它.

编辑:感谢所有的输入.正如其中一个答案所建议的那样,我最后只使用了一个等待代表返回的while循环,但是让runLoop继续如下:

while( ![messageDelegate hasFinishedOrFailed] ){
    // Allow the run loop to do some processing of the stream
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
Run Code Online (Sandbox Code Playgroud)

Jef*_*ley 24

我会尝试使用dispatch信号量.从手册页dispatch_semaphore_create(3):

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

dispatch_async(queue, ^{
    foo();
    dispatch_semaphore_signal(sema);
});

bar();

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
sema = NULL;
Run Code Online (Sandbox Code Playgroud)

呼叫dispatch_semaphore_wait()将阻塞,直到呼叫dispatch_semaphore_signal()完成.


Jos*_*ell 4

我不相信有任何方法可以在不修改的情况下做到这一点SKPSMTPMessage。该类实际上并没有使用单独的线程;而是使用单独的线程。相反,它使用NSStream 与线程的运行循环一致来避免阻塞:

[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                           forMode:NSRunLoopCommonModes];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                            forMode:NSRunLoopCommonModes];
Run Code Online (Sandbox Code Playgroud)

该流充当运行循环的输入源;然后,运行循环可以自由地处理其他事件,直到流发生某些情况,此时流会通知其委托。一切仍然发生在原始(主)线程上;如果您尝试自己阻止它,您也会阻止运行循环,并且它将无法对流执行任何操作。

其他人已经指出阻塞主线程是一个坏主意;除了用户体验问题外,系统可能会终止任何长时间不响应事件的应用程序。也就是说,您可以将整个消息设置放入后台,为其提供自己的运行循环以供流工作,并使用GCD阻塞主线程。不幸的是,我想不出一种方法让代表在没有轮询的情况下发出信号表明它已经完成。

dispatch_queue_t messageQueue;
messageQueue = dispatch_queue_create("com.valheru.messageQueue", NULL);

// dispatch_sync blocks the thread on which it's called
dispatch_sync(messageQueue, ^{
    [messageManager tryToDeliverMessage];
});
dispatch_release(messageQueue);
Run Code Online (Sandbox Code Playgroud)

哪里tryToDeliverMessage看起来像:

- (void) tryToDeliverMessage {
    // Create the message and let it run...

    // Poll a flag on the delegate
    while( ![messageDelegate hasFinishedOrFailed] ){
        // Allow the run loop to do some processing of the stream
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
    }

    return;
}
Run Code Online (Sandbox Code Playgroud)