使iOS块同步执行

时间:2011-07-07 06:38:19

标签: iphone ios cocoa-touch ios4 objective-c-blocks

如何使块同步执行,或使函数在return语句之前等待处理程序,以便数据可以从块传回?

-(id)performRequest:(id)args
{
__block NSData *data = nil;   

    [xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
        data = [NSData dataWithData:responseData];
    }];

    return data;
}

6 个答案:

答案 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)

你确定要同步吗? 如果是,您可以在块中调用(或放置)处理程序函数或使用Jignesh建议(并在处理程序完成时使用“performSelectorInMainThread”并且您想要返回值。

异步方式(稍微)更难,但更好:   - 它强制你编写干净的代码(没有方便的变量传递)   - 您可以执行其他操作,以便用户不会等待并认为您的应用程序运行缓慢。

你应该给它两到三个小时去异步。充分获得小痛苦。 您还可以查看键值观察。

答案 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;
}