2012-10-18 12 views
7

Aby podać pewien kontekst: Próbuję zaimplementować globalny moduł obsługi błędów dla błędów uwierzytelniania (przy użyciu uwierzytelniania tokena, a nie podstawowego), który powinien spróbować ponownie uwierzytelnić, a następnie powtórzyć Oryginalny powiodło się żądanie (patrz mój poprzedni pytanie: AFNetworking: Handle error globally and repeat request)AFNetworking: Dostęp do procedur obsługi zakończeń podczas ponownej operacji

Obecne podejście jest zarejestrowanie obserwatora dla AFNetworkingOperationDidFinishNotification który dokłada ponownego uwierzytelniania i (jeśli auth udało) powtarza oryginalne żądanie:

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

Jednak natknąłem się na niektóre kwestie dotyczące ukończenia bloków Operacje Żądanie:

  • Kiedy powtarzając oryginalny wniosek, oczywiście chcę jej zakończenia bloki mają być wykonywane. Jednak AFHTTPRequestOperation nie zachowuje odnośniki do przekazanych sukces i porażka bloków (patrz setCompletionBlockWithSuccess:failure:) i kopiowanie NSOperation „s completionBlock prawdopodobnie nie jest dobrym pomysłem, ponieważ dokumentacji AFURLConnectionOperation stanów: kopie

    operacyjne nie obejmują completionBlock . completionBlock często silnie przechwytuje odniesienie do self, co, o dziwo, mogłoby wskazywać na oryginalną operację podczas kopiowania.

  • Jeśli ponowne uwierzytelnianie nie powiedzie się, chcę wywołać blok błędu pierwotnego żądania. Więc znowu będę potrzebować bezpośredniego dostępu do tego.

Czy coś tu brakuje? Jakieś pomysły na alternatywne podejścia? Czy powinienem wysłać żądanie funkcji?

+0

Dobry pomysł na przesłanie prośby o funkcję, ponieważ utknąłem na niej również z odświeżaniem oauth. – shawnwall

+0

Przesłano żądanie funkcji: https://github.com/AFNetworking/AFNetworking/issues/596. Mogę wziąć to w swoje ręce później dzisiaj lub jutro. –

Odpowiedz

1

Wymyśliłem ten problem w aplikacji portfolio Art.sy. Moją ostateczną konkluzją było stworzenie podklasy NSOperationQueue, która miała funkcje tworzenia kopii różnych operacji HTTP AFNetworking po ich niepowodzeniu (i do zrobienia tego trzy razy na adres URL przed rezygnacją).

+0

Dziękuję za odpowiedź, ale czy możesz lepiej zrozumieć, w jaki sposób zostały utworzone kopie operacji? Dlaczego jest to łatwiejsze w podklasie 'NSOperationQueue' niż gdziekolwiek indziej? –

+0

Ok, po pierwsze, oto implementacja: https://gist.github.com/3968284 - Jest to podklasa 'OperationQueue', ponieważ chciałem ją zawinąć wszystkie czynności związane z operacjami i móc tworzyć kopie. Problem polega na tym, że jest bardzo specyficzny dla naszych podklas operacji, ale w naszym przypadku możemy uzyskać wszystkie te same zmienne instancji ustawione dla kopii, które następnie są ponownie uruchamiane. Ma sens? – orta

+0

Ok, widzę. Dziękuję za udostępnienie implementacji. Obawiam się jednak, że w moim przypadku użycia nie mogę po prostu odtworzyć procedur obsługi ukończeń dla wszystkich żądań w jednym miejscu. Mam bardzo różne żądania, które mają bardzo specyficzne procedury obsługi zakończeń (przetwarzanie odebranych danych itp.). Chciałbym tylko skopiować te programy obsługi ukończenia (co jest dla mnie najbardziej prostą czynnością przy ponawianiu żądań). Czy to naprawdę taki niejasny przypadek użycia/wymóg? –

0

Czy próbowałeś następujących rzeczy?

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

Zauważ, że jeśli uchwycić siebie w oryginalnym ukończenia/bloków awaryjnych (tj dostępu do żadnych Ivars) rzeczywiście dostęp do oryginalnej instancji pracy podczas wykonywania bloku zakończenia realizacji newOperation. Ale tego właśnie chcesz, prawda?

Procedura obsługi powiadomień jest wykonywana przed zakończeniem bloku operacji. Powinieneś ustawić blok zakończenia pierwotnej operacji na zero, aby uniemożliwić jej dwukrotne wykonanie.

Uwaga: blok zakończenia jest ustawiony na zero po wykonaniu (patrz AFURLConnectionOperation).

W bloku błędu authenticateWithCredentials nie należy wykonywać żadnych czynności. Oryginalna operacja zakończyła się w tym czasie i już wykonała swój blok awarii.

+0

"Ale tego właśnie chcesz, prawda?" -> Nie. Operacja 'completionBlock' jest tworzona przez AFNetworking, a nie przeze mnie. Proszę spojrzeć na implementację '- [AFHTTPRequestOperation setCompletionBlockWithSuccess: failure:]'. Tworzy to blok ukończenia, który robi rzeczy takie jak 'if ([self canced]) ...' i wywołuje bloki sukcesu/niepowodzenia dostarczone w tym bloku. –

+0

Kiedy loguję mój blok ukończenia, oryginalny jest zerowy. – quantumpotato

Powiązane problemy