2014-04-30 2 views
3

모든 초기 비동기 인증 단계가 성공하려면 여러 비동기 작업이 있습니다. 세마포어를 사용하여 인증이 완료 될 때까지 모든 보안 작업을 차단합니다. 작업은 인증이 끝날 때 획득 한 보안 토큰에 의존하기 때문에 주로 타이밍 목적으로 사용됩니다. 인증에는 네트워크 요청이 포함되며 몇 초가 걸릴 수 있습니다.많은 수를 차단하기 위해 세마포를 사용하여 모두 해제

내 코드의 난이도는 인증 후 발행 된 dispatch_semaphore_signal()이 첫 번째 세마포어 잠금을 계속할 수 있다는 신호 만 보내는 것으로 보입니다. 두 번째는 계속 차단 될 것입니다. 앞으로도 많은 모의 차단 작업이있을 수 있으며, 모두 세마포어를 기다리고 있습니다.

이 차단에 대해 명확한 방법이 있는지 궁금합니다. 각 대기중인 작업이 즉시 dispatch_semaphore_signal()을 발행하여 다음 작업을 릴리스 할 수 있다고 생각합니다. 한 번의 호출로 모든 차단 세마포를 해제 할 수 있습니까?

GCD로 더 깨끗한 방법이 있습니까? 나는 GCD에 능숙하지 못하다. 그래서 코드 스 니펫 (code snippets)이 아래의 사용법에서 도움이된다.

dispatch_semaphore_t sem = dispatch_semaphore_create(0); 

// in actuality, these 3 may be any where in the app, in different classes, methods, etc 
// so a completionHandler is not possible 
[self authentication];  // async, could take many seconds 
[self authenticatedTask1]; // async 
[self authenticatedTask2]; // async 

- (void) authentication { 
    // async url request, assume it is configured here 
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 
    // authenticate 
    authenticated = TRUE; 
    secure_token = @"4rjiofwefsdf"; // obtained during auth 
    dispatch_semaphore_signal(sem); 
    }]; 
} 

- (void) authenticatedTask1 { 
    // put on new thread, so semaphore doesn't block program 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
    if(!authenticated){ 
     // wait until authenticated 
     dispatch_semaphore_wait(sem) 
    } 
    // continue after authenticated, using secure_token 
    }); 
} 

- (void) authenticatedTask2 { 
    // put on new thread, so semaphore doesn't block program 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
    if(!authenticated){ 
     // wait until authenticated 
     dispatch_semaphore_wait(sem) 
    } 
    // continue after authenticated, using secure_token 
    }); 
} 

답변

3

인증 된 작업을 자체 일시 중단 된 발송 대기열에 넣고 인증이 성공하면 발송 대기열을 재개 할 수 있습니다.

+1

어떻게 수행 할 수 있는지 설명 할 수있는 코드 스 니펫을 제공 할 수 있습니까? – Miro

1

완료 블록에서 실행될 블록에서 실행될 메소드를 전달할 수 있습니다. 그러면 세마포어를 사용할 필요가 없습니다. 또한 당신은 끝까지 세마포어를 기다리는 dispatch_async 귀찮게 할 필요가 없습니다 것입니다 :

[self authenticationWithCompletionBlock:^{ 
    [self authenticatedTask1]; 
    [self authenticatedTask2]; 
}]; 

- (void) authenticationWithCompletionBlock:(dispatch_block_t)block { 
    // async url request, assume it is configured here 
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ 
    // authenticate 
    authenticated = TRUE; 
    secure_token = @"4rjiofwefsdf"; // obtained during auth 
    block(); 
    }]; 
} 

을 방법은 같은 클래스에있는 경우, 당신은 단지 방법 대신 직접 블록을 호출 할 수 있습니다.

그리고 당신이 (당신의 사건 authenticatedTask1authenticatedTask2에서) 모두 비동기 작업이 완료되면 알 필요가 있다면, 당신은 dispatch groups를 사용할 필요가 것입니다.

+0

3 개의 호출이 항상 로컬 인 경우이 방법이 유용합니다. 내 코드 샘플이 너무 단순 해졌지 만 사후 인증 호출은 프로젝트의 모든 위치, 별도의 클래스 등에있을 수 있습니다. 사용자가 주어진 시간에 버튼 등을 클릭 한 후에 발생할 수 있습니다. 따라서 콜백은 불가능합니다. – Miro

+1

아, 쉬운 해결책처럼 보였습니다! 'dispatch_group'을 사용해보십시오. 그 대답에 스 니펫이 있습니다. – Rich

2

매우 우아하지는 않지만 'dispatch_semaphore_wait'바로 다음에 'dispatch_semaphore_signal'을 호출 할 수 있습니다. 문제를 해결해야합니다.

- (void)authenticatedTask1 { 
    // put on new thread, so semaphore doesn't block program 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
    if(!authenticated){ 
     // wait until authenticated 
     dispatch_semaphore_wait(sem); 
     dispatch_semaphore_signal(sem); // !!! 
    } 
    // continue after authenticated, using secure_token 
    }); 
} 
+0

나는 그것을 또한주의했다. 그것이 내가 이것을 처리 할 더 좋은 방법이되어야한다고 결정한 요지입니다 ... – Miro