2012-10-18 3 views
7

일부 컨텍스트를 제공하려면 : 인증 오류 (토큰 인증을 사용하지 않고 기본)를 사용하여 전역 오류 처리기를 구현하려고합니다. 원래 실패한 요청 (내 앞의 질문을 참조하십시오 AFNetworking: Handle error globally and repeat request) :AFNetworking : 작업을 다시 시도 할 때 완료 핸들러에 액세스

- (void)operationDidFinish:(NSNotification *)notification 
{ 
    AFHTTPRequestOperation *operation = (AFHTTPRequestOperation *)[notification object]; 

    if(![operation isKindOfClass:[AFHTTPRequestOperation class]]) { 
     return; 
    } 

    if(403 == [operation.response statusCode]) { 
     // try to re-authenticate and repeat the original request 
     [[UserManager sharedUserManager] authenticateWithCredentials... 
      success:^{ 
       // repeat original request 

       // AFHTTPRequestOperation *newOperation = [operation copy]; // copies too much stuff, eg. response (although the docs suggest otherwise) 
       AFHTTPRequestOperation *newOperation = [[AFHTTPRequestOperation alloc] initWithRequest:operation.request]; 

       // PROBLEM 1: newOperation has no completion blocks. How to use the original success/failure blocks here? 

       [self enqueueHTTPRequestOperation:newOperation]; 
      } 
      failure:^(NSError *error) { 
       // PROBLEM 2: How to invoke failure block of original operation? 
      } 
     ]; 
    } 
} 

(인증이 성공하면) 현재의 접근 방식은 재 인증을 수행하고, AFNetworkingOperationDidFinishNotification에 대한 관찰자를 등록하는 것입니다

를 원래 요청을 반복 그러나, 나는 완성 블록에 관한 몇 가지 문제를 발견했다. 요청 작업 :

  • 원래 요청을 반복 할 때 분명히 완성 블록이 실행되기를 원합니다. 그러나 AFHTTPRequestOperationAFURLConnectionOperation 상태의 문서로 전달 된 성공과 실패 블록에 대한 참조 (setCompletionBlockWithSuccess:failure: 참조) 및 복사 NSOperationcompletionBlock 아마 좋은 생각이 아니다를 유지하지 않습니다

    동작 사본 completionBlock에 포함되지 않습니다 . completionBlock은 종종 self에 대한 참조를 강력하게 캡처합니다. 복사 할 경우 놀랍게도 작동을 가리 킵니다.

  • 재 인증에 실패하면 원래 요청의 실패 블록을 호출하고 싶습니다. 그래서, 다시, 나는 이것에 직접 접근 할 필요가있다.

여기에 뭔가가 빠졌습니까? 대체 접근법에 대한 아이디어가 있습니까? 기능 요청을 제출해야합니까?

+0

기능 요청을 제출하는 것이 좋습니다. 또한 oauth 새로 고침으로이 문제에 봉착했습니다. – shawnwall

+0

기능 요청을 제출했습니다 : https://github.com/AFNetworking/AFNetworking/issues/596. 나는 오늘이나 내일 후에 나 자신의 손을 잡을지도 모른다. –

답변

1

Art.sy 님의 포트폴리오 앱에서이 문제를 해결했습니다. 나의 궁극적 인 결론은 NSUperationQueue 서브 클래스를 만드는 것이었다.이 서브 클래스는 일단 실패하면 다양한 AFNetworking HTTP 조작의 사본을 생성한다. (URL 당 3 번까지이를 포기하기 전에 수행한다.)

+0

답해 주셔서 감사합니다.하지만 작업 사본을 정확히 작성한 방법에 대해 좀 더 자세히 알고 싶습니까? 'NSOperationQueue' 서브 클래스에서 다른 곳보다 더 쉬운 이유는 무엇입니까? –

+0

먼저, 구현은 다음과 같습니다. https://gist.github.com/3968284 - 작업을 처리하고 사본을 생성 할 수있는 모든 처리 방법을 래핑하기 때문에 'OperationQueue' 하위 클래스입니다. 여기서 문제는 작업 하위 클래스에 매우 한정적이지만, 우리의 경우에는 다시 실행되는 복사본에 대해 동일한 인스턴스 변수를 설정할 수 있습니다. 이해가 되니? – orta

+0

알았어. 구현을 공유해 주셔서 감사합니다. 그러나 유스 케이스에서는 모든 요청에 ​​대해 완료 핸들러를 한 곳에서 다시 만들 수는 없습니다. 매우 구체적인 완료 처리기 (받은 데이터 처리 등)가있는 매우 다른 요청이 있습니다. 나는 그 완료 핸들러를 복사하기를 원할 것이다 (나에게있어서, 요청을 다시 시도 할 때 가장 직접적으로 할 일이다). 이것은 정말로 그렇게 모호한 사용 사례/요구 사항입니까? –

0

다음을 시도 했습니까? 원래 완료/실패 블록 자체를 포착하면 newOperation 완료 블록을 실행할 때 실제로 원래 작업 인스턴스에 액세스 (즉, 임의의 인스턴스 변수를 액세스하는) 것을

// set success/failure block of original operation 
[newOperation setCompletionBlock:[operation.completionBlock copy]]; 
[operation setCompletionBlock:nil]; 

참고. 그러나 이것은 당신이 실제로 원하는 것입니다, 그렇죠?

알림 핸들러는 작업의 완료 블록 전에 실행됩니다. 원래 작업의 완료 블록을 nil로 설정하여 두 번 실행하지 못하게해야합니다.

완료 블록은 실행 후 nil로 설정됩니다 (AFURLConnectionOperation 참조).

authenticateWithCredentials 실패 블록에서 아무것도하지 말아야합니다. 원래 작업은 그 시점에 끝났으며 이미 해당 오류 블록을 실행했습니다.

+0

"하지만이게 네가 실제로 원하는거야, 그렇지?" 작업의 completionBlock은 AFNetworking에 의해 만들어지며, 혼자서는 생성되지 않습니다. '- [AFHTTPRequestOperation setCompletionBlockWithSuccess : failure :]'의 구현을 살펴보십시오. 이것은'if ([self cancelled]) ...'와 같은 일을하는 완성 블록을 만들고 그 블록에서 제공된 성공/실패 블록을 호출합니다. –

+0

완료 블록을 로그 할 때 원래 블록은 nil입니다. – quantumpotato

관련 문제