web-dev-qa-db-ja.com

iOSブロックを同期的に実行させる

ブロックを同期的に実行させたり、関数にreturnステートメントの前にハンドラーを待機させたりして、データをブロックから戻すことができるようにするにはどうすればよいですか?

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

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

    return data;
}
22
Sathya

この場合、セマフォを使用できます。

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

セマフォは、シグナルが受信されるまでそれ以降のステートメントの実行をブロックします。これにより、関数が途中で戻らないようになります。

27
dev gr

ほとんどの場合、非同期の方が優れています。ただし、同期が必要な場合:

-(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は、もちろん、これは完了ブロックと実行ループが同じスレッド上にある場合にのみ機能すると述べています。私が知っている多くの(ほとんどの)COMPLETIONハンドラーはそのように機能するので、原則として有効であると思いました。

上記はスレッドセーフではありません
セマフォか何かを使用するかもしれません。
また、私はこれを宣伝しないと言いました

3
Daij-Djan

返されたデータを処理するメソッドを追加して、ブロック内でそれを呼び出すことができます。

-(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 
    }];
}
2
redisant