Problem
I'm currently grabbing weather forecast information with [NSData dataWithContentsOfURL: url]
. The problem with this is that if there are errors during the URL fetch, I just get back a nil.
An alternative to the method [NSData dataWithContentsOfURL:options:error:]
will provide error info to me, but what my calling function wants is the data, not a possible error that it must diagnose and deal with.
Requirements
What I'd like is a single function that a client can call to grab a URL that "absolutely will not stop" until the URL has been loaded.
I don't want the function's clients to need to think about:
- Timeouts.
- Internet connections being unavailable or not.
- The device being locked or the app moving in to the background.
- The actual site in question being down.
- Other sources of error.
Other design objectives
The function should treat the device and remote site nicely – it should not swamp it with requests resends that will certainly fail, for example.
The caller should be able to abort the attempt if it desires, so it'll want to have a handle to the request allowing it to kill it off.
The function should be asynchronous, taking a block to handle the result when it eventually arrives.
For extra marks a method for the calling function to be sent error diagnostics would be nice. Again, I think a block would work nicely for this. The needn't do anything about the error, because the function isn't going to give up, but it can use it to provide useful feedback to a user. For example, to allay their concerns, or prompt them to take remedial action (turn networking back on, for example).
Possible interface
So the a client call to the function might go like this:
_currentGrabber = [TenaciousURLGrabber
grabberForURL: myURL
withCompletionAndDiagnosticsHandler:
^(NSData* finalData, ErrorObject *error){
if(data)
{
// Update my UI using data.
}
else
{
// Update my UI to show `[error localisedError];`
}
}];
If the client gets bored or decides that the fetch isn't worth it any more, it can do:
[_currentGrabber invalidate];
Implementation thoughts.
It'd be great if this pretty much already exists. Otherwise, I'm interested in suggestions on implementing this functionality.
I should probably be making use of NSURLSession
instead of the older NSURLConnection
. The possibility of background (out of process) downloads looks useful? Any tips beyond this?
The function should use SCNetworkReachability
as demonstrated in the Reachability sample application following failure to determine when its worth a retry attempt.