如何包装异步类以使其同步?使用NSRunLoop?

ric*_*ver 6 multithreading objective-c nsrunloop

我目前正在开发一个iPhone应用程序,我有一个来自第三方的库,它有异步行为,但是我想用自己的类包装并使它看起来是同步的.

这个库中的中心类,我们称之为Connection类,有几个函数在调用委托类的实例上的方法时解析它们的最终结果.我正在尝试做的是包装这个类和委托,使它看起来是同步的而不是异步的.如果我在Java中这样做,我会使用FutureTask或CountdownLatch或只是join().但我不确定目标C中最好的方法.

我首先创建了一个NSThread扩展,NFCThread,它符合上面提到的委托协议.我的想法是我将init和NFCThread,将NFCThread实例传递给Connection的setDelegate方法,启动线程然后在Connection上调用异步方法.我的期望是NFCThread实例上的三个委托方法之一将被调用,最终导致线程退出.

为了模拟连接,我做了以下操作.我在NFCThread中添加了一个NSConditionalLock:

joinLock = [[NSConditionLock alloc] initWithCondition:NO];
Run Code Online (Sandbox Code Playgroud)

调用Connection的代码看起来像这样:

NFCThread *t = [[NFCThread alloc] init];
[connection setDelegate:t];
[t start];

[connection openSession];
// Process errors, etc...

[t.joinLock lockWhenCondition:YES];
[t.joinLock unlock];
[t release];
[connection setDelegate:nil];
Run Code Online (Sandbox Code Playgroud)

委托的协议有三种方法.在NFCThread中我实现了每个方法,如下所示:

- (void)didReceiveMessage:(CommandType)cmdType 
                     data:(NSString *)responseData 
               length:(NSInteger)length {
    NSLog(@"didReceiveMessage");
    // Do something with data and cmdType...
    [joinLock lock];
    [joinLock unlockWithCondition:YES];
    callBackInvoked = YES;
}
Run Code Online (Sandbox Code Playgroud)

我重载了NFCThread的主要方法,以便它不断循环.像这样的东西:

while (!callBackInvoked) { ; }
Run Code Online (Sandbox Code Playgroud)

我发现这不是一个好主意,因为它会导致cpu使用率通过屋顶.所以我尝试使用我在这个网站上找到的一些例子的运行循环:

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

while (!callBackInvoked) {
    [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Run Code Online (Sandbox Code Playgroud)

在我的两个实现中,主线程总是被阻塞,并且似乎没有调用任何委托方法.但是,我知道库正常运行,并且通常会调用委托方法.

我觉得我在这里遗漏了一些明显的东西.任何帮助非常感谢.

丰富

Fir*_*eer 0

好吧,这里有一些不同的问题,我正在考虑从哪里开始。

但是,为了让我们理解您想要完成的任务,当您说您希望调用“看起来”同步时,您的意思是您希望调用被阻止吗?您是从主线程进行此调用吗?如果是这样,那么您似乎有意阻止主线程。

请记住,第三方库可能正在主运行循环上安排事件。您可以创建自己的运行循环并在另一个线程中运行它,但是您是否告诉其他库将该运行循环用于其事件?(例如,它可能正在发出安排在您已阻止的主运行循环上的异步网络请求)

我会重新考虑一下您在做什么,但首先我们需要知道您的意图是否是阻止您发出此调用的线程。另外,需要支持iPhoneOS 3.x吗?