2012-10-18 19 views
7

Để cung cấp cho một số bối cảnh: Tôi đang cố gắng triển khai trình xử lý lỗi toàn cầu cho các lỗi xác thực (sử dụng xác thực mã thông báo, không cơ bản), nên cố gắng xác thực lại và sau đó lặp lại ban đầu yêu cầu không thành (xem câu hỏi trước đây của tôi: AFNetworking: Handle error globally and repeat request)AFNetworking: Truy cập vào trình xử lý hoàn tất khi thử lại hoạt động

cách tiếp cận hiện nay là phải đăng ký một người quan sát cho AFNetworkingOperationDidFinishNotification mà không tái thẩm định và (nếu auth thành công) lặp đi lặp lại yêu cầu ban đầu:

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

Tuy nhiên, tôi tình cờ gặp một số vấn đề liên quan đến các khối hoàn thành yêu cầu hoạt động:

  • Khi lặp lại yêu cầu ban đầu, tôi rõ ràng muốn khối hoàn thành được thực thi. Tuy nhiên, AFHTTPRequestOperation không giữ lại tài liệu tham khảo cho sự thành công và thất bại khối thông qua (xem setCompletionBlockWithSuccess:failure:) và sao chép NSOperation 's completionBlock có lẽ không phải là một ý tưởng tốt, như tài liệu cho AFURLConnectionOperation trạng thái:

    Operation bản không bao gồm completionBlock . completionBlock thường mạnh mẽ chụp một tham chiếu đến self, trong đó, có lẽ đáng ngạc nhiên, nếu không sẽ trỏ đến hoạt động gốc khi được sao chép.

  • Trong trường hợp xác thực lại không thành công, tôi muốn gọi khối lỗi của yêu cầu ban đầu. Vì vậy, một lần nữa, tôi cần truy cập trực tiếp vào điều này.

Tôi có thiếu gì đó ở đây không? Bất kỳ ý tưởng cho phương pháp tiếp cận thay thế? Tôi có nên gửi yêu cầu tính năng không?

+0

Ý tưởng tốt để gửi yêu cầu tính năng, vì tôi bị kẹt trên điều này cũng với làm mới oauth. – shawnwall

+0

Đã gửi yêu cầu tính năng: https://github.com/AFNetworking/AFNetworking/issues/596. Tôi có thể có được bàn tay của riêng tôi về điều này sau ngày hôm nay hoặc ngày mai. –

Trả lời

1

Tôi đã tìm ra vấn đề này trong ứng dụng danh mục đầu tư của Art.sy. Kết luận cuối cùng của tôi là tạo ra một lớp con NSOperationQueue có chức năng tạo các bản sao của nhiều hoạt động HTTP AFNetworking khác nhau khi chúng không thành công (và để làm điều này tối đa ba lần cho mỗi URL trước khi từ bỏ.)

+0

Cảm ơn câu trả lời của bạn, nhưng bạn có thể cung cấp một số thông tin chi tiết hơn về cách chính xác bạn đã tạo bản sao của các hoạt động không? Tại sao điều này dễ dàng hơn trong một lớp con 'NSOperationQueue' hơn một nơi khác? –

+0

Ok, trước hết, đây là triển khai: https://gist.github.com/3968284 - Đây là lớp con 'OperationQueue' vì tôi muốn nó bao bọc tất cả việc xử lý các hoạt động đã cho và có thể tạo bản sao. Vấn đề ở đây là nó rất cụ thể đối với các lớp con hoạt động của chúng ta, nhưng trong trường hợp của chúng ta, chúng ta có thể nhận được tất cả các biến thể hiện tương tự được thiết lập cho các bản sao mà sau đó được chạy lại. Có lý? – orta

+0

Ok, tôi hiểu rồi. Cảm ơn bạn đã chia sẻ việc triển khai. Tuy nhiên, tôi e rằng trong trường hợp sử dụng của tôi, tôi không thể chỉ tạo lại các trình xử lý hoàn thành cho tất cả các yêu cầu ở một nơi duy nhất. Tôi có các yêu cầu rất khác nhau có trình xử lý hoàn thành rất cụ thể (xử lý dữ liệu đã nhận, v.v.). Tôi chỉ muốn sao chép các trình xử lý hoàn thành (mà, đối với tôi, là điều dễ hiểu nhất cần làm khi thử lại các yêu cầu). Đây có thực sự là trường hợp sử dụng không rõ ràng/yêu cầu không? –

0

Bạn đã thử làm như sau?

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

Lưu ý rằng nếu bạn chụp tự trong việc hoàn thành gốc/khối thất bại (ví dụ: truy cập vào bất kỳ ivars) bạn thực sự truy cập Ví dụ hoạt động ban đầu khi thực hiện khối hoàn thành newOperation. Nhưng đây là những gì bạn muốn thực sự, phải không?

Trình xử lý thông báo được thực hiện trước khối hoàn thành của thao tác. Vì vậy, bạn nên đặt khối hoàn thành của hoạt động ban đầu thành 0, để ngăn chặn nó thực hiện hai lần.

Lưu ý khối hoàn thành được đặt thành 0 sau khi nó đã được thực hiện (xem AFURLConnectionOperation).

Trong khối xác thựcWithCredentials xác thực, bạn không nên làm gì cả. Hoạt động ban đầu đã kết thúc tại thời điểm đó và đã thực thi khối lỗi của nó.

+0

"Nhưng đây là những gì bạn muốn thực sự, phải không?" -> No. 'completeBlock' của hoạt động được tạo bởi AFNetworking, không phải bởi bản thân tôi. Vui lòng xem xét việc thực hiện '- [AFHTTPRequestOperation setCompletionBlockWithSuccess: failure:]'. Điều này xây dựng một khối hoàn thành thực hiện những việc như 'if ([tự hủy]) ...' và gọi các khối thành công/thất bại được cung cấp trong khối đó. –

+0

Khi tôi đăng nhập khối hoàn thành của tôi, bản gốc là không. – quantumpotato

Các vấn đề liên quan