如何等待异步方法结束?

Eth*_*ick 1 iphone multithreading asynchronous objective-c synchronous

我有一个工具包,我需要使用(与远程服务接口).此工具包查询远程服务并询问结果.它以异步方式执行此操作,在大多数情况下这是好的,但不是用于创建简洁的方法.我想制作类似于以下的方法:

-(NSArray *)getAllAccounts {
    NSString *query = @"SELECT name FROM Account";
    //Sets "result" to the query response if no errors.
    //queryResult:error:context: is called when the data is received
    [myToolkit query:query target:self selector:@selector(queryResult:error:context:) context:nil];

    //Wait?

    return result.records;
}
Run Code Online (Sandbox Code Playgroud)

问题是,在工具包中,方法使用@selector相互调用,而不是直接调用,因此获取返回值很困难.此外,实际查询使用:

NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:aRequest delegate:self] autorelease];
Run Code Online (Sandbox Code Playgroud)

哪个是异步的.当从服务接收到数据时,我的方法很久以前就返回了......没有信息.所以我的问题是:有没有办法暂停执行,直到数据被返回?我可以使用第二个线程来完成这个,以便在主线程休息时获取数据(或使用3个​​线程,因此主线程不会休息吗?)

我不想编辑工具包来改变他们的方法(或添加一个新的)来实现同步,那么有没有办法按我想要的方法制作一个方法?

OzB*_*dit 5

您可能要考虑不要将它全部同步,尤其是如果您的帖子中的示例代码在主应用程序线程上运行.如果这样做,主线程将阻止UI,应用程序将停止响应,直到远程事务完成.

因此,如果你真的坚持同步方法,那么你肯定应该在后台线程中进行,这样UI就不会反应迟钝,这实际上会导致你的应用程序被iphone上的操作系统杀死.

要在后台线程中完成工作,我强烈建议使用Grand Central Dispatch的东西,即NSBlockOperation.它将使您不必实际创建和管理线程,并使您的代码非常整洁.

要执行同步操作,请查看NSCondition类文档.您可以执行以下操作:

NSCondition* condition = ...;
bool finished = NO;

-(NSArray *)getAllAccounts {
    [condition lock];
    NSString *query = @"SELECT name FROM Account";
    //Sets "result" to the query response if no errors.
    //queryResult:error:context: is called when the data is received
    [myToolkit query:query target:self selector:@selector(queryResult:error:context:) context:nil];

    while (!finished)
        [condition wait]; 

    [condition unlock];
    return result.records;
}
Run Code Online (Sandbox Code Playgroud)

然后在工具包调用的方法中提供您要执行的结果:

- (void) queryResult:error:context: {
    //  Deal with results
    [condition lock]
    finished = YES;
    [condition signal];
    [condition unlock];
}
Run Code Online (Sandbox Code Playgroud)

您可能希望在类声明中封装"condition"和"finished"变量.

希望这可以帮助.

更新:这是一些代码将工作卸载到后台线程:

NSOperationQueue* queue = [NSOperationQueue new];
[queue addOperationWithBlock:^{
    //  Invoke getAllAccounts method
}];
Run Code Online (Sandbox Code Playgroud)

当然,您可以保留队列以供以后使用,并将工作的实际排队移动到方法调用中以使事情变得更整洁.