如何使块同步执行,或使函数在return语句之前等待处理程序,以便数据可以从块传回?
-(id)performRequest:(id)args
{
__block NSData *data = nil;
[xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
data = [NSData dataWithData:responseData];
}];
return data;
}
答案 0 :(得分:26)
在这种情况下,您可以使用信号量。
-(id)performRequest:(id)args
{
__block NSData *data = nil;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
data = [NSData dataWithData:responseData];
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return data;
}
信号量将阻止执行进一步的语句,直到收到信号,这将确保您的函数不会过早返回。
答案 1 :(得分:4)
异步几乎总是更好。但如果你想要同步:
-(id)performRequest:(id)args
{
__block NSData *data = nil;
[xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
data = [NSData dataWithData:responseData];
}];
while(!data) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
return data;
}
声明: CocoaCouchDeveloper说当然这只有在完成块和runloop在同一个线程上时才有效。 我认为因为很多(大多数)COMPLETION处理程序我知道这样做但原则上它是有效的。
以上不是线程安全的
使用信号量或其他东西。
我还说我不推广这个
答案 2 :(得分:2)
您可以添加一个方法来处理返回的数据并在块中调用它:
-(void)performRequest:(id)args{
__block NSData *data = nil;
[xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
data = [NSData dataWithData:responseData];
[self processData:data]; //method does something with the data
}];
}
答案 3 :(得分:-1)
您可以在另一个线程中执行同步请求,例如下面的代码
-(void)performRequest:(id)args
{
NSURLResponse *response = nil;
NSError *error = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
}
从主线程中你可以调用此
[self performSelectorInBackground:@selector(performRequest:) withObject:args];
或者您可以使用以下方法执行异步请求
[NSURLConnection alloc]initWithRequest:request delegate:self];
并实现NSURLConnection的委托方法
答案 4 :(得分:-1)
异步方式(稍微)更难,但更好: - 它强制你编写干净的代码(没有方便的变量传递) - 您可以执行其他操作,以便用户不会等待并认为您的应用程序运行缓慢。
你应该给它两到三个小时去异步。充分获得小痛苦。 您还可以查看键值观察。
答案 5 :(得分:-3)
你可以这样做。
-(id)performRequest:(id)args
{
__block NSData *data = nil;
[xyzclass performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
dispatch_sync( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
data = [NSData dataWithData:responseData];
});
}];
return data;
}