Using OperationQueue for your URL requests (with a built-in retry mechanism).
Here is the detailed lifespan of an URLRequestOperation
:
- Init. Not much to tell here…
- Request Launch:
-
First, the URL is processed for running. Which means the method
processURLRequestForRunning
is called. This is an override point for subclasses if they want to prevent the request to run depending on certain condition, or if they want to modify the URL Request prior running it.This processing might take some time, or be expensive resource-wise, which is why you can specify a queue on which the processing will be done. (This is the
queueForProcessingURLRequestForRunning
property.)If the processing fails (returns an error), the operation will go to the error processing step (4) with the given error (the operation might be retried later depending on the error processing result).
-
Next, the session task is created. The creation of the task and the behavior of the operation will differ depending on the delegate of the URL session given to the operation.
-
Session delegate is an instance of
URLRequestOperationSessionDelegate
: The task is created withurlSessionTaskForURLRequest(_:withDelegate)
(which can be overridden if need be). By default, in this method, the session delegate is told to forward the delegate method regarding this specific task to the operation (the delegate of an URL session is a global delegate and cannot be set by task without this hack AFAIK).If subclasses overwrite this method and decide to work a different way for the delegate method, they will be responsible for receiving the data and treating it, then must call
urlSession(_:task:didCompleteWithError:)
when the task is done. -
Session delegate is kind of another class of
nil
: The task is created with theurlSessionTaskForURLRequest(_:,withDataCompletionHandler:, downloadCompletionHandler:)
.
-
-
Finally the task is launched.
-
- While the request is live:
- For data tasks, when the session delegate is an instance of
URLRequestOperationSessionDelegate
:- A URL response is received. First the method
errorForResponse(_:)
will check whether the response is appropriate (correct status code and mime type, or other pre-filters). Then theurlResponseProcessor
will be called if the previous check passes. Both method can cancel the session task if they deem the response not worthy of continuing. - Data is then received…
- At one point (
urlSession(_:task:didCompleteWithError:)
), the task will finish.processEndOfTask(error:)
(private) is called to check what to do from here.
- A URL response is received. First the method
- For data tasks, or tasks whose delegate is not of expected class, there
will be no response processing. The next step will be when the task is
finished:
processEndOfTask(error:)
is called.
- For data tasks, when the session delegate is an instance of
- Processing the end of the task (
processEndOfTask(error:)
):-
If there is already a final error (eg. operation cancelled), the operation is ended here.
-
Otherwise the
computeRetryInfo(sourceError:completionHandler:)
method is called on thequeueForComputingRetryInfo
(computing the retry info might be an expensive operation). This method is reponsible for telling whether the operation should be retried, and after which delay. The default implementation will check the error. For a network lost for instance, the operation should be retried for idempotent HTTP requests. The delay respects an exponential backoff by default. Subclasses can override to implement their own logic and behavior. This is actually the most important override point for the operation.The
computeRetryInfo
method will also allow to decide whether some “early retrying” techniques should be setup. Or you can setup your own. There are two built-in retrying techniques: TheReachabilityObserver
which will simply check when the network is reachable again and theOther Success Observer
which will trigger a retry when another URLRequestOperation for the same host succeeds.If you decide to write your own “early retrying” methods, you should overwrite
removeObserverForEarlyRetrying()
and remove your observers in your implementation. Do not forget to call super!If the operation is told to be retried, when it is retried, we simply go back to step 2. (The URL is re-processed, etc.)
-
This project was originally created by François Lamboley while working at happn.