我有一个需要使用的工具包(与远程服务接口)。此工具包查询远程服务并询问结果。它以异步方式执行此操作,在大多数情况下是 good ,但不是用于创建简洁方法。我想制作类似于以下的方法:
-(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;
}
问题是,在工具包中,方法使用@selector相互调用,而不是直接调用,因此获取返回值很困难。此外,实际查询使用:
NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:aRequest delegate:self] autorelease];
哪个是异步的。当从服务接收到数据时,我的方法很久以前就返回了......没有信息。所以我的问题是:有没有办法暂停执行,直到数据被返回?我可以使用第二个线程来完成这个,以便在主线程休息时获取数据(或使用3个线程,因此主线程不会休息吗?)
我不想编辑工具包来改变他们的方法(或添加新的方法)以实现同步,那么有没有办法按我想要的方法制作方法?
答案 0 :(得分: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;
}
然后在工具包调用的方法中提供你要做的结果:
- (void) queryResult:error:context: {
// Deal with results
[condition lock]
finished = YES;
[condition signal];
[condition unlock];
}
您可能希望在类声明中封装“condition”和“finished”变量。
希望这有帮助。
更新:以下是将工作卸载到后台线程的一些代码:
NSOperationQueue* queue = [NSOperationQueue new];
[queue addOperationWithBlock:^{
// Invoke getAllAccounts method
}];
当然,您可以保留队列以供以后使用,并将工作的实际排队移动到方法调用中以使事情变得更整洁。
答案 1 :(得分:3)
等待的方法是从当前代码返回。在您指定的异步回调方法中,完成等待后执行的操作。这有什么困难?
主UI线程中的任何同步等待都会阻止用户界面并让用户认为您的应用已被锁定,这可能比您认为代码不够简洁要差得多。