2011-06-13 273 views
1

我有一个工具包,我需要使用(与远程服务接口)。该工具包查询远程服务并询问结果。它是异步执行的,在大多数情况下它是好的,但不是用于创建简洁的方法。我要让方法类似于以下:如何等待异步方法结束?

-(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; 
} 

的问题是,该工具包内的方法相互调用使用@选择,而不是直接调用,因此让返回值是困难的。此外,实际查询使用:

NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:aRequest delegate:self] autorelease]; 

这是异步的。当从服务接收到数据时,我的方法早已返回......没有这些信息。所以我的问题是这样的:有没有办法暂停执行,直到数据被返回?我可以使用第二个线程来获得主线程休息时的数据(或使用3个​​线程,因此主线程不会休息?)

我不想编辑工具包以更改其方法或添加一个新的)是同步的,那么是否有办法按照我的意愿创建一个方法?

回答

5

您可能想要考虑不让它全部同步,特别是如果您的文章中的示例代码在您的主应用程序线程上运行。如果这样做,主线程将阻止用户界面,应用程序将停止响应,直到远程事务完成。

因此,如果你确实坚持同步方法,那么你应该在后台线程中做到这一点,以便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; 
} 

然后在通过工具包调用的方法提供的结果,你会怎么做:

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

你可能会想封装“条件”和你的类声明中的“完成”变量。

希望这会有所帮助。

更新:下面是一些代码来卸载工作提高到一个后台线程:

NSOperationQueue* queue = [NSOperationQueue new]; 
[queue addOperationWithBlock:^{ 
    // Invoke getAllAccounts method 
}]; 

当然,你可以保持队列各地供以后使用和移动工作的实际排队到你的方法内打电话让事情更整洁。

+0

看起来,构建你的代码,我的执行到while循环,并“永远等待”,而不是响应queryResult方法。想法?感谢您的回应! – 2011-06-13 16:50:11

+0

嗯,queryResult方法实际上是否被调用?你可以在那里放置断点以确保条件得到信号?我应该指出,如果您的queryResult方法由于某种原因未被调用,您的getAllAccounts方法将永远阻塞。 – OzBandit 2011-06-13 17:20:32

+0

另外,尝试在while循环中添加一些跟踪输出以查看条件是否被解除阻塞。也许它不会因为某些原因而对变量进行修改。 – OzBandit 2011-06-13 17:22:42

3

等待的方式是从您当前的代码返回。在等待之后完成您想要完成的任务,使用您指定的异步回调方法。这有什么困难?

主UI线程中的任何同步等待都会阻止用户界面,并让用户认为您的应用程序已被锁定,这可能远远超出您认为代码不够简洁的想法。