0
나는 다음과 같은 구조가 여러 가지 방법이

:중첩 방법

- (void) doSomethingWithCompletion: (void (^)(NSError *error)) completion { 
    __block NSError *fetchError = nil; 

    dispatch_group_t dispatchGroup = dispatch_group_create(); 

    for (Item* item in self.items) 
    { 
     dispatch_group_enter(dispatchGroup); 

     // fetchError = fetch online data 
    } 

    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(),^{ 
     if (completion) 
      completion(fetchError); 
    }); 
} 

내 목표는 서로 후 몇 doSomethings를 실행하는 것입니다, 그래서 수 있도록이 같은 :

[self doSomethingAWithCompletion: ^(NSArray *results NSError *error) { 
    if (error == nil) { 
     [self doSomethingBWithArray: results withCompletion: ^(NSError *error) { 
     if (error == nil) { 
      [self doSomethingCWithCompletion: ^(NSError *error) { 
       if (error == nil) { 
        // done!! 
       } 
      }]; 
     }]; 
}]; 

내가 고민하는 것은 두 번째 코드 블록 (말장난 없음)입니다. 모든 방법을 중첩 시키거나 다른 해결책이 있습니까? 중요한 것은이

는 등

또한, doSomethingBWithCompletiondoSomethingAWithCompletion에서 생성되는 데이터 등을 사용 doSomethingAWithCompletion이 완료되기 전에 doSomethingBWithCompletion 시작 할 수 없으며, doSomethingBWithCompletion이 완료 될 때까지 doSomethingCWithCompletion 요구 기다려야한다는 것입니다

편집 : 많은 생각과 리팩터링 및 코드 단순화를 거친 후에 위에서 설명한대로 내포 된 방법을 사용하고 결과 배열에 @property을 사용하여 두 가지 기능으로 끝낼 수있었습니다.

중요한 것은이
+0

을하지만, 나는 그랜드 센트럴 디스패치로 충분히 확고하지 않다. 당신이했던 것처럼 당신은 블록을 체인에 넣을 수있다. 정확히 어디에서 싸우고 있는가? – Gulliva

+0

나는 중첩하는 것이 가장 좋은 방법인지 잘 모르겠다. 작동하는 것은 의미하지만 읽고 유지하기가 어렵습니다. 대안이 있는지 확인하고 싶습니다. – Koen

+1

물론 당신은 맞지만 생각합니다. 그것을 연결하는 일반적인 방법입니다. 가독성을 높이기 위해 다음과 같이 메소드를 둘러 쌀 수 있습니다. - (void) doSomthingB {[self doSomethingBWithCompletion :^(NSError * error) { if (error == nil) { }]; .. 블록의 결과는 처음의 결과에 의존하지 않습니다? – Gulliva

답변

1

, 코멘트에 의하면 등

, doSomethingBWithCompletion이 doSomethingAWithCompletion 전에 시작할 수 없다는 것입니다 수행하고, doSomethingBWithCompletion이 완료 될 때까지 doSomethingCWithCompletion 기다릴 필요가 :

블록의 결과는 처음의 결과에 의존하지 않습니다?

그리고

예들이 있습니다. 예를 들어, 첫 번째 doSomething에서 어느 항목이 구형인지, 두 번째 doSomething에서 업데이트 된 항목을 다운로드하고 구문 분석하며, 세 번째 doSomething에서는 저장소에 저장합니다.

은 (BTW : 당신은 정말 당신의 질문에이 정보를 추가해야합니다) 작업은 이전 작업의 결과 (뿐만 아니라 실행)에 의존하는 경우

을, 당신은 중첩 블록을 가지고있다. 완료 블록으로 전달 된 데이터가 없으므로 코드가 이와 같이 보이지 않습니다.

이러한 종속성이없는 경우 개인용 직렬 발송 대기열을 사용할 수 있습니다. 그러나 블록 간 전달되는 데이터를 보유하는 관리자 클래스와 유사한 경우이 솔루션이 사용자의 경우에 해당됩니다. 그러나 이것은 매우 비 응집성 인 것으로 보인다.

+0

예,'doSomethingBWithCompletion'은'doSomethingAWithCompletion' 등에서 생성 된 데이터를 사용합니다; 내 질문에 이것을 추가했습니다. – Koen

+0

네, 그게 더 명확 해집니다. –

1

목표 -C에 약속을 추가하려는 공동체 시도가있을 수 있습니다. 여기에 필요한 것이기 때문에 좋을 것입니다. 완전히 새로운 라이브러리에 커밋하지 않고 비동기 작업을 재귀 적으로 수행하여 중첩을 처리 할 수 ​​있습니다. 예를 들어 다음과 같습니다.

매개 변수가없는 작업부터 시작하십시오. 그리고 배열 결과 ...여기

- (void)firstOpWithCompletion:(void (^)(NSArray *, NSError *))completion { 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 
     NSArray *components = [@"this is an array of strings from the FIRST op" componentsSeparatedByString:@" "]; 
     if (completion) { 
      completion(components, nil); 
     } 
    }); 
} 

내 대답에로 이전이 편집에, 이제 배열에 배열 PARAM을하고 결과를 몇 ...

- (void)secondOpWithParam:(NSArray *)array completion:(void (^)(NSArray *, NSError *))completion { 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 
     if (completion) { 
      NSArray *components = [@"these strings are from the SECOND op" componentsSeparatedByString:@" "]; 
      NSArray *result = [array arrayByAddingObjectsFromArray:components]; 
      if (completion) { 
       completion(result, nil); 
      } 
     } 
    }); 
} 

- (void)thirdOpWithParam:(NSArray *)array completion:(void (^)(NSArray *, NSError *))completion { 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue, ^{ 
     if (completion) { 
      NSArray *components = [@"these strings are from the THIRD op" componentsSeparatedByString:@" "]; 
      NSArray *result = [array arrayByAddingObjectsFromArray:components]; 
      if (completion) { 
       NSLog(@"we did it. returning %@", result); 
       completion(result, nil); 
      } 
     } 
    }); 
} 

// ...as many as these as you need 

을, 우리는 단지 PARAM 패스를 추가 처음과 중간 통화에서 ...

- (void)doSeveralThingsInSequence:(NSArray *)todo param:(NSArray *)param { 
    if (todo.count == 0) return; 
    // you could generalize further here, by passing a "final" block and run that before the return 

    NSString *nextTodo = todo[0]; 
    SEL sel = NSSelectorFromString(nextTodo); 

    IMP imp = [self methodForSelector:sel]; 
    void (*func)(id, SEL, NSArray *, void (^)(NSArray *, NSError *)) = (void *)imp; 
    func(self, sel, param, ^(NSArray *result, NSError *error) { 
     if (!error) { 
      NSArray *remainingTodo = [todo subarrayWithRange:NSMakeRange(1, todo.count-1)]; 
      [self doSeveralThingsInSequence:remainingTodo param:result]; 
     } 
    }); 
} 

는 코드를 통해 스테핑 :이 방법의 보석금을 아무 존재하지 않는 경우는, 그렇지 않으면 다음 선택 이름을 사용 전달 된 배열에서 C 함수 구현을 가져 와서 호출하고 나머지 선택자에 대해 프로세스를 시작하는 완료 블록을 호출 스택에 배치합니다.

마지막으로 doEverything은 시작하기 위해 첫 번째 연산을 호출 한 다음 배열 입력을 다음 배열 입력으로 전달하는 작업 목록 (임의로 긴 목록 일 수 있음)을 실행하기 시작합니다. (당신은 내가 정확히 게시 된이 테스트 예상 출력 본

- (void)doEverything { 
    [self firstOpWithCompletion:^(NSArray *array, NSError *error) { 
     NSArray *todo = @[ @"secondOpWithParam:completion:", @"thirdOpWithParam:completion:" ]; 
     [self doSeveralThingsInSequence:todo param:array]; 
    }]; 
} 

더 체인을 따라 id 년대를 통과하여이를 일반화 수 : 내가 문제가되지한다고 생각합니다 그래서

(
this, 
is, 
an, 
array, 
of, 
strings, 
from, 
the, 
FIRST, 
op, 
these, 
strings, 
are, 
from, 
the, 
SECOND, 
op, 
these, 
strings, 
are, 
from, 
the, 
THIRD, 
op 
) 
+0

이 방법을 사용하면'doSomething'에서 다음으로 데이터를 전달할 수 있습니까? – Koen

+0

@Koen - 물론입니다. 코드에서 실제로 일어나고있는 것을 게시하십시오. 나는 앞으로 6 시간 정도 그것을 얻을 수있다. – danh

+0

약속은 작품을 병렬 처리하려고합니다. 그는 * 그들을 대기열에 넣기를 원합니다. –