I think you can probably do this with a fairly trivial custom NSURLProtocol
.
In your canInitWithRequest:
method, call the setProperty:forKey:inRequest:
method on NSURLProtocol
to set a custom start time key for the request. Then reject the request (by returning NO
) and allow the normal HTTP protocol to handle the request normally.
When you get a response, call property:forKey:inRequest:
to get the start time.
With that said, there's no guarantee that the request really will start immediately after the call to canInitWithRequest:
, and because there's no good way to subclass the original HTTP protocol handler class (to wrap the startLoading
method), this may or may not be precise enough. I'm not sure.
So if that doesn't work, then to improve the accuracy, you would have to create a full-blown protocol that:
- Returns
YES
in canInitWithRequest:
(except if the start time has already been set for that request)
- Creates a new URL session in its
startLoading
method (to ensure that the request will start instantly)
- Adds the start time to the request
- Begins the request in that new session
But even that will not necessarily give you precise timing if the request is happening while the app is in the background or if the discretionary
flag is set on the session configuration. That approach also won't work very easily if you're using more than one session with different configurations. It is, however, probably the best you can do in terms of accuracy, because I doubt that there's any way to swizzle the built-in HTTP protocol class (if such a class even exists).