How to do structured programming using blocks in Objective-C - objective-c

When using methods which return blocks they can be very convenient.
However, when you have to string a few of them together it gets messy really quickly
for instance, you have to call 4 URLs in succession:
[remoteAPIWithURL:url1 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
[remoteAPIWithURL:url3 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
//succes!!!
}];
}];
}];
}];
So for every iteration I go one level deeper, and I don't even handle errors in the nested blocks yet.
It gets worse when there is an actual loop. For instance, say I want to upload a file in 100 chunks:
- (void) continueUploadWithBlockNr:(int)blockNr
{
if(blocknr>=100)
{
//success!!!
}
[remoteAPIUploadFile:file withBlockNr:blockNr success:^(int status)
{
[self continueUploadWithBlockNr:blockNr];
}];
}
This feels very unintuitive, and gets very unreadable very quick.
In .Net they solved all this using the async and await keyword, basically unrolling these continuations into a seemingly synchronous flow.
What is the best practice in Objective C?

Your question immediately made me think of recursion. Turns out, Objective-c blocks can be used in recursion. So I came up with the following solution, which is easy to understand and can scale to N tasks pretty nicely.
// __block declaration of the block makes it possible to call the block from within itself
__block void (^urlFetchBlock)();
// Neatly aggregate all the urls you wish to fetch
NSArray *urlArray = #[
[NSURL URLWithString:#"http://www.google.com"],
[NSURL URLWithString:#"http://www.stackoverflow.com"],
[NSURL URLWithString:#"http://www.bing.com"],
[NSURL URLWithString:#"http://www.apple.com"]
];
__block int urlIndex = 0;
// the 'recursive' block
urlFetchBlock = [^void () {
if (urlIndex < (int)[urlArray count]){
[self remoteAPIWithURL:[urlArray objectAtIndex:index]
success:^(int theStatus){
urlIndex++;
urlFetchBlock();
}
failure:^(){
// handle error.
}];
}
} copy];
// initiate the url requests
urlFetchBlock();

One way to reduce nesting is to define methods that return the individual blocks. In order to facilitate the data sharing which is done "auto-magically" by the Objective C compiler through closures, you would need to define a separate class to hold the shared state.
Here is a rough sketch of how this can be done:
typedef void (^WithStatus)(int);
#interface AsyncHandler : NSObject {
NSString *_sharedString;
NSURL *_innerUrl;
NSURL *_middleUrl;
WithStatus _innermostBlock;
}
+(void)handleRequest:(WithStatus)innermostBlock
outerUrl:(NSURL*)outerUrl
middleUrl:(NSURL*)middleUrl
innerUrl:(NSURL*)innerUrl;
-(WithStatus)outerBlock;
-(WithStatus)middleBlock;
#end
#implementation AsyncHandler
+(void)handleRequest:(WithStatus)innermostBlock
outerUrl:(NSURL*)outerUrl
middleUrl:(NSURL*)middleUrl
innerUrl:(NSURL*)innerUrl {
AsyncHandler *h = [[AsyncHandler alloc] init];
h->_innermostBlock = innermostBlock;
h->_innerUrl = innerUrl;
h->_middleUrl = middleUrl;
[remoteAPIWithURL:outerUrl success:[self outerBlock]];
}
-(WithStatus)outerBlock {
return ^(int success) {
_sharedString = [NSString stringWithFormat:#"Outer: %i", success];
[remoteAPIWithURL:_middleUrl success:[self middleBlock]];
};
}
-(WithStatus)middleBlock {
return ^(int success) {
NSLog("Shared string: %#", _sharedString);
[remoteAPIWithURL:_innerUrl success:_innermostBlock];
};
}
#end
Note: All of this assumes ARC; if you are compiling without it, you need to use Block_copy in the methods returning blocks. You would also need to do a copy in the calling code below.
Now your original function can be re-written without the "Russian doll" nesting, like this:
[AsyncHandler
handleRequest:^(int status){
//succes!!!
}
outerUrl:[NSURL #"http://my.first.url.com"]
middleUrl:[NSURL #"http://my.second.url.com"]
innerUrl:[NSURL #"http://my.third.url.com"]
];

Iterative algorithm:
Create a __block variable (int urlNum) to keep track of the current URL (inside an NSArray of them).
Have the onUrlComplete block fire off the next request until all URLs have been loaded.
Fire the first request.
When all URLs have been loaded, do the "//success!" dance.
Code written without the aid of XCode (meaning, there may be compiler errors -- will fix if necessary):
- (void)loadUrlsAsynchronouslyIterative:(NSArray *)urls {
__block int urlNum = 0;
void(^onUrlComplete)(int) = nil; //I don't remember if you can call a block from inside itself.
onUrlComplete = ^(int status) {
if (urlNum < urls.count) {
id nextUrl = urls[urlNum++];
[remoteAPIWithURL:nextUrl success:onUrlComplete];
} else {
//success!
}
}
onUrlComplete(0); //fire first request
}
Recursive algorithm:
Create a method to load all the remaining URLs.
When remaining URLs is empty, fire "onSuccess".
Otherwise, fire request for the next URL and provide a completion block that recursively calls the method with all but the first remaining URLs.
Complications: we declared the "onSuccess" block to accept an int status parameter, so we pass the last status variable down (including a "default" value).
Code written without the aid of XCode (bug disclaimer here):
- (void)loadUrlsAsynchronouslyRecursive:(NSArray *)remainingUrls onSuccess:(void(^)(int status))onSuccess lastStatus:(int)lastStatus {
if (remainingUrls.count == 0) {
onSuccess(lastStatus);
return;
}
id nextUrl = remainingUrls[0];
remainingUrls = [remainingUrls subarrayWithRange:NSMakeRange(1, remainingUrls.count-1)];
[remoteAPIWithUrl:nextUrl onSuccess:^(int status) {
[self loadUrlsAsynchronouslyRecursive:remainingUrls onSuccess:onSuccess lastStatus:status];
}];
}
//fire first request:
[self loadUrlsAsynchronouslyRecursive:urls onSuccess:^(int status) {
//success here!
} lastStatus:0];
Which is better?
The iterative algorithm is simple and concise -- if you're comfortable playing games with __block variables and scopes.
Alternatively, the recursive algorithm doesn't require __block variables and is fairly simple, as recursive algorithms go.
The recursive implementation is more re-usable that the iterative one (as implemented).
The recursive algorithm might leak (it requires a reference to self), but there are several ways to fix that: make it a function, use __weak id weakSelf = self;, etc.
How easy would it be to add error-handling?
The iterative implementation can easily be extended to check the value of status, at the cost of the onUrlComplete block becoming more complex.
The recursive implementation is perhaps not as straight-forward to extend -- primarily because it is re-usable. Do you want to cancel loading more URLs when the status is such-and-such? Then pass down a status-checking/error-handling block that accepts int status and returns BOOL (for example YES to continue, NO to cancel). Or perhaps modify onSuccess to accept both int status and NSArray *remainingUrls -- but you'll need to call loadUrlsAsynchronouslyRecursive... in your onSuccess block implementation.

You said (in a comment), “asynchronous methods offer easy asynchronisity without using explicit threads.” But your complaint seems to be that you're trying to do something with asynchronous methods, and it's not easy. Do you see the contradiction here?
When you use a callback-based design, you sacrifice the ability to express your control flow directly using the language's built-in structures.
So I suggest you stop using a callback-based design. Grand Central Dispatch (GCD) makes it easy (that word again!) to perform work “in the background”, and then call back to the main thread to update the user interface. So if you have a synchronous version of your API, just use it in a background queue:
- (void)interactWithRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// This block runs on a background queue, so it doesn't block the main thread.
// But it can't touch the user interface.
for (NSURL *url in #[url1, url2, url3, url4]) {
int status = [remoteAPI syncRequestWithURL:url];
if (status != 0) {
dispatch_async(dispatch_get_main_queue(), ^{
// This block runs on the main thread, so it can update the
// user interface.
[self remoteRequestFailedWithURL:url status:status];
});
return;
}
}
});
}
Since we're just using normal control flow, it's straightforward to do more complicated things. Say we need to issue two requests, then upload a file in chunks of at most 100k, then issue one more request:
#define AsyncToMain(Block) dispatch_async(dispatch_get_main_queue(), Block)
- (void)uploadFile:(NSFileHandle *)fileHandle withRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int status = [remoteAPI syncRequestWithURL:url1];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url1 status:status]; });
return;
}
status = [remoteAPI syncRequestWithURL:url2];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url2 status:status]; });
return;
}
while (1) {
// Manage an autorelease pool to avoid accumulating all of the
// 100k chunks in memory simultaneously.
#autoreleasepool {
NSData *chunk = [fileHandle readDataOfLength:100 * 1024];
if (chunk.length == 0)
break;
status = [remoteAPI syncUploadChunk:chunk];
if (status != 0) {
AsyncToMain(^{ [self sendChunkFailedWithStatus:status]; });
return;
}
}
}
status = [remoteAPI syncRequestWithURL:url4];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url4 status:status]; });
return;
}
AsyncToMain(^{ [self uploadFileSucceeded]; });
});
}
Now I'm sure you're saying “Oh yeah, that looks great.” ;^) But you might also be saying “What if RemoteAPI only has asynchronous methods, not synchronous methods?”
We can use GCD to create a synchronous wrapper for an asynchronous method. We need to make the wrapper call the async method, then block until the async method calls the callback. The tricky bit is that perhaps we don't know which queue the async method uses to invoke the callback, and we don't know if it uses dispatch_sync to call the callback. So let's be safe by calling the async method from a concurrent queue.
- (int)syncRequestWithRemoteAPI:(id<RemoteAPI>)remoteAPI url:(NSURL *)url {
__block int outerStatus;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[remoteAPI asyncRequestWithURL:url completion:^(int status) {
outerStatus = status;
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);
return outerStatus;
}
UPDATE
I will respond to your third comment first, and your second comment second.
Third Comment
Your third comment:
Last but not least, your solution of dedicating a separate thread to wrap around the synchronous version of a call is more costly than using the async alternatives. a Thread is an expensive resource, and when it is blocking you basically have lost one thread. Async calls (the ones in the OS libraries at least) are typically handled in a much more efficient way. (For instance, if you would request 10 urls at the same time, chances are it will not spin up 10 threads (or put them in a threadpool))
Yes, using a thread is more expensive than just using the asynchronous call. So what? The question is whether it's too expensive. Objective-C messages are too expensive in some scenarios on current iOS hardware (the inner loops of a real-time face detection or speech recognition algorithm, for example), but I have no qualms about using them most of the time.
Whether a thread is “an expensive resource” really depends on the context. Let's consider your example: “For instance, if you would request 10 urls at the same time, chances are it will not spin up 10 threads (or put them in a threadpool)”. Let's find out.
NSURL *url = [NSURL URLWithString:#"http://1.1.1.1/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
for (int i = 0; i < 10; ++i) {
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(#"response=%# error=%#", response, error);
}];
}
So here I am using Apple's own recommended +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] method to send 10 requests asynchronously. I've chosen the URL to be non-responsive, so I can see exactly what kind of thread/queue strategy Apple uses to implement this method. I ran the app on my iPhone 4S running iOS 6.0.1, paused in the debugger, and took a screen shot of the Thread Navigator:
You can see that there are 10 threads labeled com.apple.root.default-priority. I've opened three of them so you can see that they are just normal GCD queue threads. Each calls a block defined in +[NSURLConnection sendAsynchronousRequest:…], which just turns around and calls +[NSURLConnection sendSynchronousRequest:…]. I checked all 10, and they all have the same stack trace. So, in fact, the OS library does spin up 10 threads.
I bumped the loop count from 10 to 100 and found that GCD caps the number of com.apple.root.default-priority threads at 64. So my guess is the other 36 requests I issued are queued up in the global default-priority queue, and won't even start executing until some of the 64 “running” requests finish.
So, is it too expensive to use a thread to turn an asynchronous function into a synchronous function? I'd say it depends on how many of these you plan to do simultaneously. I would have no qualms if the number's under 10, or even 20.
Second Comment
Which brings me to your second comment:
However, when you have: do these 3 things at the same time, and when 'any' of them is finished then ignore the rest and do these 3 calls at the same time and when 'all' of them finish then succes.
These are cases where it's easy to use GCD, but we can certainly combine the GCD and async approaches to use fewer threads if you want, while still using the languages native tools for control flow.
First, we'll make a typedef for the remote API completion block, just to save typing later:
typedef void (^RemoteAPICompletionBlock)(int status);
I'll start the control flow the same way as before, by moving it off the main thread to a concurrent queue:
- (void)complexFlowWithRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
First we want to issue three requests simultaneously and wait for one of them to succeed (or, presumably, for all three to fail).
So let's say we have a function, statusOfFirstRequestToSucceed, that issues any number of asynchronous remote API requests and waits for the first to succeed. This function will provide the completion block for each async request. But the different requests might take different arguments… how can we pass the API requests to the function?
We can do it by passing a literal block for each API request. Each literal block takes the completion block and issues the asynchronous remote API request:
int status = statusOfFirstRequestToSucceed(#[
^(RemoteAPICompletionBlock completion) {
[remoteAPI requestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI anotherRequestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI thirdRequestWithCompletion:completion];
}
]);
if (status != 0) {
AsyncToMain(^{ [self complexFlowFailedOnFirstRoundWithStatus:status]; });
return;
}
OK, now we've issued the three first parallel requests and waited for one to succeed, or for all of them to fail. Now we want to issue three more parallel requests and wait for all to succeed, or for one of them to fail. So it's almost identical, except I'm going to assume a function statusOfFirstRequestToFail:
status = statusOfFirstRequestToFail(#[
^(RemoteAPICompletionBlock completion) {
[remoteAPI requestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI anotherRequestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI thirdRequestWithCompletion:completion];
}
]);
if (status != 0) {
AsyncToMain(^{ [self complexFlowFailedOnSecondRoundWithStatus:status]; });
return;
}
Now both rounds of parallel requests have finished, so we can notify the main thread of success:
[self complexFlowSucceeded];
});
}
Overall, that seems like a pretty straightforward flow of control to me, and we just need to implement statusOfFirstRequestToSucceed and statusOfFirstRequestToFail. We can implement them with no extra threads. Since they are so similar, we'll make them both call on a helper function that does the real work:
static int statusOfFirstRequestToSucceed(NSArray *requestBlocks) {
return statusOfFirstRequestWithStatusPassingTest(requestBlocks, ^BOOL (int status) {
return status == 0;
});
}
static int statusOfFirstRequestToFail(NSArray *requestBlocks) {
return statusOfFirstRequestWithStatusPassingTest(requestBlocks, ^BOOL (int status) {
return status != 0;
});
}
In the helper function, I'll need a queue in which to run the completion blocks, to prevent race conditions:
static int statusOfFirstRequestWithStatusPassingTest(NSArray *requestBlocks,
BOOL (^statusTest)(int status))
{
dispatch_queue_t completionQueue = dispatch_queue_create("remote API completion", 0);
Note that I will only put blocks on completionQueue using dispatch_sync, and dispatch_sync always runs the block on the current thread unless the queue is the main queue.
I'll also need a semaphore, to wake up the outer function when some request has completed with a passing status, or when all requests have finished:
dispatch_semaphore_t enoughJobsCompleteSemaphore = dispatch_semaphore_create(0);
I'll keep track of the number of jobs not yet finished and the status of the last job to finish:
__block int jobsLeft = requestBlocks.count;
__block int outerStatus = 0;
When jobsLeft becomes 0, it means that either I've set outerStatus to a status that passes the test, or that all jobs have completed. Here's the completion block where I'll the work of tracking whether I'm done waiting. I do it all on completionQueue to serialize access to jobsLeft and outerStatus, in case the remote API dispatches multiple completion blocks in parallel (on separate threads or on a concurrent queue):
RemoteAPICompletionBlock completionBlock = ^(int status) {
dispatch_sync(completionQueue, ^{
I check to see if the outer function is still waiting for the current job to complete:
if (jobsLeft == 0) {
// The outer function has already returned.
return;
}
Next, I decrement the number of jobs remaining and make the completed job's status available to the outer function:
--jobsLeft;
outerStatus = status;
If the completed job's status passes the test, I set jobsLeft to zero to prevent other jobs from overwriting my status or singling the outer function:
if (statusTest(status)) {
// We have a winner. Prevent other jobs from overwriting my status.
jobsLeft = 0;
}
If there are no jobs left to wait on (because they've all finished or because this job's status passed the test), I wake up the outer function:
if (jobsLeft == 0) {
dispatch_semaphore_signal(enoughJobsCompleteSemaphore);
}
Finally, I release the queue and the semaphore. (The retains will be later, when I loop through the request blocks to execute them.)
dispatch_release(completionQueue);
dispatch_release(enoughJobsCompleteSemaphore);
});
};
That's the end of the completion block. The rest of the function is trivial. First I execute each request block, and I retain the queue and the semaphore to prevent dangling references:
for (void (^requestBlock)(RemoteAPICompletionBlock) in requestBlocks) {
dispatch_retain(completionQueue); // balanced in completionBlock
dispatch_retain(enoughJobsCompleteSemaphore); // balanced in completionBlock
requestBlock(completionBlock);
}
Note that the retains aren't necessary if you're using ARC and your deployment target is iOS 6.0 or later.
Then I just wait for one of the jobs to wake me up, release the queue and the semaphore, and return the status of the job that woke me:
dispatch_semaphore_wait(enoughJobsCompleteSemaphore, DISPATCH_TIME_FOREVER);
dispatch_release(completionQueue);
dispatch_release(enoughJobsCompleteSemaphore);
return outerStatus;
}
Note that the structure of statusOfFirstRequestWithStatusPassingTest is fairly generic: you can pass any request blocks you want, as long as each one calls the completion block and passes in an int status. You could modify the function to handle a more complex result from each request block, or to cancel outstanding requests (if you have a cancellation API).

While researching this myself I bumped into a port of Reactive Extensions to Objective-C. Reactive Extensions is like having the ability to querying a set of events or asynchronous operations. I know it has had a big uptake under .Net and JavaScript, and now apparently there is a port for Objective-C as well
https://github.com/blog/1107-reactivecocoa-for-a-better-world
Syntax looks tricky. I wonder if there is real world experience with it for iPhone development and if it does actually solve this issue elegantly.

I tend to wrap big nested block cluster f**** like you describe in subclasses of NSOperation that describe what the overall behaviour that your big nest block cluster f*** is actually doing (rather than leaving them littered throughout other code).
For example if your following code:
[remoteAPIWithURL:url1 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
[remoteAPIWithURL:url3 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
//succes!!!
}];
}];
}];
}];
is intended to get an authorise token and then sync something perhaps it would be an NSAuthorizedSyncOperation… I'm sure you get the gist. Benefits of this are nice tidy bundles of behaviour wrapped up in a class with one place to edit them if things change down the line. My 2¢.

In NSDocument the following methods are available for serialization:
Serialization
– continueActivityUsingBlock:
– continueAsynchronousWorkOnMainThreadUsingBlock:
– performActivityWithSynchronousWaiting:usingBlock:
– performAsynchronousFileAccessUsingBlock:
– performSynchronousFileAccessUsingBlock:
I'm just digging into this, but it seems like this would be a good place to start.

Not sure if that is want you where looking for? Though all objects in the array need different times to complete the all appear in the order the where submitted to the queue.
typedef int(^SumUpTill)(int);
SumUpTill sum = ^(int max){
int i = 0;
int result = 0;
while (i < max) {
result += i++;
}
return result;
};
dispatch_queue_t queue = dispatch_queue_create("com.dispatch.barrier.async", DISPATCH_QUEUE_CONCURRENT);
NSArray *urlArray = #[ [NSURL URLWithString:#"http://www.google.com"],
#"Test",
[sum copy],
[NSURL URLWithString:#"http://www.apple.com"]
];
[urlArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
dispatch_barrier_async(queue, ^{
if ([obj isKindOfClass:[NSURL class]]) {
NSURLRequest *request = [NSURLRequest requestWithURL:obj];
NSURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"index = %d, response=%# error=%#", idx, response, error);
}
else if ([obj isKindOfClass:[NSString class]]) {
NSLog(#"index = %d, string %#", idx, obj);
}
else {
NSInteger result = ((SumUpTill)obj)(1000000);
NSLog(#"index = %d, result = %d", idx, result);
}
});
}];

Related

Incrementing a Variable from an Asynchronous Block in Objective-C

I have run into a bit of a conundrum with a service I am working on in objective-c. The purpose of the service is to parse through a list of core-data entities and download a corresponding image file for each object. The original design of the service was choking my web-server with too many simultaneous download requests. To get around that, I moved the code responsible for executing the download request into a recursive method. The completion handler for each download request will call the method again, thus ensuring that each download will wait for the previous one to complete before dispatching.
Where things get tricky is the code responsible for actually updating my core-data model and the progress indicator view. In the completion handler for the download, before the method recurses, I make an asynchronous call the a block that is responsible for updating the core data and then updating the view to show the progress. That block needs to have a variable to track how many times the block has been executed. In the original code, I could simply have a method-level variable with block scope that would get incremented inside the block. Since the method is recursive now, that strategy no longer works. The method level variable would simply get reset on each recursion. I can't simply pass the variable to the next level either thanks to the async nature of the block calls.
I'm at a total loss here. Can anyone suggest an approach for dealing with this?
Update:
As matt pointed out below, the core issue here is how to control the timing of the requests. After doing some more research, I found out why my original code was not working. As it turns out, the timeout interval starts running as soon as the first task is initiated, and once the time is up, any additional requests would fail. If you know exactly how much time all your requests will take, it is possible to simply increase the timeout on your requests. The better approach however is to use an NSOperationQueue to control when the requests are dispatched. For a great example of how to do this see: https://code-examples.net/en/q/19c5248
If you take this approach, keep in mind that you will have to call the completeOperation() method of each operation you create on the completion handler of the downloadTask.
Some sample code:
-(void) downloadSkuImages:(NSArray *) imagesToDownload onComplete:(void (^)(BOOL update,NSError *error))onComplete
{
[self runSerializedRequests:imagesToDownload progress:weakProgress downloaded:0 index:0 onComplete:onComplete ];
}
-(void)runSerializedRequests:(NSArray *) skuImages progress:(NSProgress *) progress downloaded:(int) totalDownloaded index:(NSUInteger) index onComplete:(void (^)(BOOL update,NSError *error))onComplete
{
int __block downloaded = totalDownloaded;
TotalDownloadProgressBlock totalDownloadProgressBlock = ^BOOL (SkuImageID *skuImageId, NSString *imageFilePath, NSError *error) {
if(error==nil) {
downloaded++;
weakProgress.completedUnitCount = downloaded;
//save change to core-data here
}
else {
downloaded++;
weakProgress.completedUnitCount = downloaded;
[weakSelf setSyncOperationDetail:[NSString stringWithFormat:#"Problem downloading sku image %#",error.localizedDescription]];
}
if(weakProgress.totalUnitCount==weakProgress.completedUnitCount) {
[weakSelf setSyncOperationIndicator:SYNC_INDICATOR_WORKING];
[weakSelf setSyncOperationDetail:#"All product images up to date"];
[weakSelf setSyncOperationStatus:SYNC_STATUS_SUCCESS];
weakProgress.totalUnitCount = 1;
weakProgress.completedUnitCount = 1;
onComplete(false,nil);
return true;
}
return false;
};
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:nil
completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
NSLog(#"finished download %u of %lu", index +1, (unsigned long)skuImages.count);
if(error != nil)
{
NSLog(#"Download failed for URL: %# with error: %#",skuImage.url, error.localizedDescription);
}
else
{
NSLog(#"Download succeeded for URL: %#", skuImage.url);
}
dispatch_async(dispatch_get_main_queue(), ^(void){
totalDownloadProgressBlock(skuImageId, imageFilePath, error);
});
[self runSerializedRequests:manager skuImages:skuImages progress:progress downloaded:downloaded index:index+1 onComplete:onComplete ];
}];
NSLog(#"Starting download %u of %lu", index +1, (unsigned long)skuImages.count);
[downloadTask resume];
}
The original design of the service was choking my web-server with too many simultaneous download requests. To get around that, I moved the code responsible for executing the download request into a recursive method.
But that was never the right way to solve the problem. Use a single persistent custom NSURLSession with your own configuration, and set the configuration's httpMaximumConnectionsPerHost.

When will completionBlock be called for dependencies in NSOperation

From the docs:
The completion block you provide is executed when the value returned by the isFinished method changes to YES. Thus, this block is executed by the operation object after the operation’s primary task is finished or cancelled.
I'm using RestKit/AFNetworking, if that matters.
I have multiple dependencies in my NSOperation in a OperationQueue. I use the completion block to set some variables (appending the results to an array) that my child requires.
(task1,...,taskN) -> taskA
taskA addDependency: task1-taskN
Will taskA receive incomplete data since the child can execute before the completion block is fired?
Reference
Do NSOperations and their completionBlocks run concurrently?
I did a simple test by adding a sleep in my completion block and I had a different result. The completion block runs in the main thread. While all the completion block are sleeping, the child task ran.
As I discuss below under "a few observations", you have no assurances that this final dependent operation will not start before your other sundry AFNetworking completion blocks have finished. It strikes me that if this final operation really needs to wait for these completion blocks to finish, then you have a couple of alternatives:
Use semaphores within each of the n the completion blocks to signal when they're done and have the completion operation wait for n signals; or
Don't queue this final operation up front, but rather have your completion blocks for the individual uploads keep track of how many pending uploads are still incomplete, and when it falls to zero, then initiate the final "post" operation.
As you pointed out in your comments, you could wrap your invocation of the AFNetworking operation and its completion handler in your own operation, at which point you can then use the standard addDependency mechanism.
You could abandon the addDependency approach (which adds an observer on the isFinished key of the operation upon which this operation is dependent, and once all those dependencies are resolved, performs the isReady KVN; the problem being that this can theoretically happen before your completion block is done) and replace it with your own isReady logic. For example, imagine you had a post operation which you could add your own key dependencies and remove them manually in your completion block, rather than having them removed automatically upon isFinished. Thus, you custom operation
#interface PostOperation ()
#property (nonatomic, getter = isReady) BOOL ready;
#property (nonatomic, strong) NSMutableArray *keys;
#end
#implementation PostOperation
#synthesize ready = _ready;
- (void)addKeyDependency:(id)key {
if (!self.keys)
self.keys = [NSMutableArray arrayWithObject:key];
else
[self.keys addObject:key];
self.ready = NO;
}
- (void)removeKeyDependency:(id)key {
[self.keys removeObject:key];
if ([self.keys count] == 0)
self.ready = YES;
}
- (void)setReady:(BOOL)ready {
if (ready != _ready) {
[self willChangeValueForKey:#"isReady"];
_ready = ready;
[self didChangeValueForKey:#"isReady"];
}
}
- (void)addDependency:(NSOperation *)operation{
NSAssert(FALSE, #"You should not use addDependency with this custom operation");
}
Then, your app code could do something like, using addKeyDependency rather than addDependency, and explicitly either removeKeyDependency or cancel in the completion blocks:
PostOperation *postOperation = [[PostOperation alloc] init];
for (NSInteger i = 0; i < numberOfImages; i++) {
NSURL *url = ...
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSString *key = [url absoluteString]; // or you could use whatever unique value you want
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// update your model or do whatever
// now inform the post operation that this operation is done
[postOperation removeKeyDependency:key];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// handle the error any way you want
// perhaps you want to cancel the postOperation; you'd either cancel it or remove the dependency
[postOperation cancel];
}];
[postOperation addKeyDependency:key];
[queue addOperation:operation];
}
[queue addOperation:postOperation];
This is using AFHTTPRequestOperation, and you'd obviously replace all of this logic with the appropriate AFNetworking operation for your upload, but hopefully it illustrates the idea.
Original answer:
A few observations:
As I think you concluded, when your operation completes, it (a) initiates its completion block; (b) makes the queue available for other operations (either operations that had not yet started because of maxConcurrentOperationCount, or because of dependencies between the operations). I do not believe that you have any assurances that the completion block will be done before that next operation commences.
Empirically, it looks like the dependent operation does not actually trigger until after the completion blocks are done, but (a) I don't see that documented anywhere and (b) this is moot because if you're using AFNetworking's own setCompletionBlockWithSuccess, it ends up dispatching the block asynchronously to the main queue (or the defined successCallbackQueue), thereby thwarting any (undocumented) assurances of synchrony.
Furthermore, you say that the completion block runs in the main thread. If you're talking about the built in NSOperation completion block, you have no such assurances. In fact, the setCompletionBlock documentation says:
The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it. For example, if you have a custom thread for coordinating the completion of the operation, you could use the completion block to ping that thread.
But if you're talking about one of AFNetworking's custom completion blocks, e.g. those that you might set with AFHTTPRequestOperation's setCompletionBlockWithSuccess, then, yes, it's true that those are generally dispatched back to the main queue. But AFNetworking does this using the standard completionBlock mechanism, so the above concerns still apply.
It matters if your NSOperation is a subclass of AFHTTPRequestOperation. AFHTTPRequestOperation uses the NSOperation's property completionBlock for its own purpose in method setCompletionBlockWithSuccess:failure. In that case, don't set the property completionBlock yourself!
It seems, AFHTTPRequestOperation's success and failure handler will run on the main thread.
Otherwise, the execution context of NSOperation's completion block is "undefined". That means, the completion block can execute on any thread/queue. In fact it executes on some private queue.
IMO, this is the preferred approach, unless the execution context shall be explicitly specified by the call-site. Executing completion handlers on threads or queues which instances are accessible (the main thread for example) can easily cause dead locks by an unwary developer.
Edit:
If you want to start a dependent operation after the completion block of the parent operation has been finished, you can solve that by making the completion block content itself a NSBlockOperation (a new parent) and add this operation as a dependency to the children operation and start it in a queue. You may realize, that this quickly becomes unwieldy, though.
Another approach would require an utility class or class library which is especially suited to solve asynchronous problems in a more concise and easy way. ReactiveCocoa would be capable to solve such (an easy) problem. However, it's unduly complex and it actually has a "learning curve" - and a steep one. I wouldn't recommend it, unless you agree to spend a few weeks in learning it and have a lot other asynchronous use cases and even much more complex ones.
A simpler approach would utilize "Promises" which are pretty common in JavaScript, Python, Scala and a few other languages.
Now, please read carefully, the (easy) solution is actually below:
"Promises" (sometimes called Futures or Deferred) represent the eventual result of an asynchronous task. Your fetch request is such asynchronous task. But instead specifying a completion handler, the asynchronous method/task returns a Promise:
-(Promise*) fetchThingsWithURL:(NSURL*)url;
You obtain the result - or the error - with registering a success handler block or a failure handler block like so:
Promise* thingsPromise = [self fetchThingsWithURL:url];
thingsPromise.then(successHandlerBlock, failureHandlerBlock);
or, the blocks inlined:
thingsPromise.then(^id(id things){
// do something with things
return <result of success handler>
}, ^id(NSError* error){
// Ohps, error occurred
return <result of failure handler>
});
And shorter:
[self fetchThingsWithURL:url]
.then(^id(id result){
return [self.parser parseAsync:result];
}, nil);
Here, parseAsync: is an asynchronous method which returns a Promise. (Yes, a Promise).
You might wonder how to get the result from the parser?
[self fetchThingsWithURL:url]
.then(^id(id result){
return [self.parser parseAsync:result];
}, nil)
.then(^id(id parserResult){
NSLog(#"Parser returned: %#", parserResult);
return nil; // result not used
}, nil);
This actually starts async task fetchThingsWithURL:. Then when finished successfully, it starts async task parseAsync:. Then when this finished successfully, it prints the result, otherwise it prints the error.
Invoking several asynchronous tasks sequentially, one after the other, is called "continuation" or "chaining".
Note that the whole statement above is asynchronous! That is, when you wrap the above statement into a method, and execute it, the method returns immediately.
You might wonder how to catch any errors, say fetchThingsWithURL: fails, or parseAsync::
[self fetchThingsWithURL:url]
.then(^id(id result){
return [self.parser parseAsync:result];
}, nil)
.then(^id(id parserResult){
NSLog(#"Parser returned: %#", parserResult);
return nil; // result not used
}, nil)
.then(/*succes handler ignored*/, ^id (NSError* error){
// catch any error
NSLog(#"ERROR: %#", error);
return nil; // result not used
});
Handlers execute after the corresponding task has been finished (of course). If the task succeeds, the success handler will be called (if any). If the tasks fails, the error handler will be called (if any).
Handlers may return a Promise (or any other object). For example, if an asynchronous task finished successfully, its success handler will be invoked which starts another asynchronous task, which returns the promise. And when this is finished, yet another one can be started, and so force. That's "continuation" ;)
You can return anything from a handler:
Promise* finalResult = [self fetchThingsWithURL:url]
.then(^id(id result){
return [self.parser parseAsync:result];
}, nil)
.then(^id(id parserResult){
return #"OK";
}, ^id(NSError* error){
return error;
});
Now, finalResult will either eventually become the value #"OK" or an NSError.
You can save the eventual results into an array:
array = #[
[self task1],
[self task2],
[self task3]
];
and then continue when all tasks have been finished successfully:
[Promise all:array].then(^id(results){
...
}, ^id (NSError* error){
...
});
Setting a promise's value will be called: "resolving". You can resolve a promise only ONCE.
You may wrap any asynchronous method with a completion handler or completion delegates into a method which returns a promise:
- (Promise*) fetchUserWithURL:(NSURL*)url
{
Promise* promise = [Promise new];
HTTPOperation* op = [[HTTPOperation alloc] initWithRequest:request
success:^(NSData* data){
[promise fulfillWithValue:data];
}
failure:^(NSError* error){
[promise rejectWithReason:error];
}];
[op start];
return promise;
}
Upon completion of the task, the promise can be "fulfilled" passing it the result value, or it can be "rejected" passing it the reason (error).
Depending on the actual implementation, a Promise can also be cancelled. Say, you hold a reference to a request operation:
self.fetchUserPromise = [self fetchUsersWithURL:url];
You can cancel the asynchronous task as follows:
- (void) viewWillDisappear:(BOOL)animate {
[super viewWillDisappear:animate];
[self.fetchUserPromise cancel];
self.fetchUserPromise = nil;
}
In order to cancel the associated async task, register a failure handler in the wrapper:
- (Promise*) fetchUserWithURL:(NSURL*)url
{
Promise* promise = [Promise new];
HTTPOperation* op = ...
[op start];
promise.then(nil, ^id(NSError* error){
if (promise.isCancelled) {
[op cancel];
}
return nil; // result unused
});
return promise;
}
Note: you can register success or failure handlers, when, where and as many as you want.
So, you can do a lot with promises - and even more than in this brief introduction. If you read up to here, you might get an idea how to solve your actual problem. It's right there - and it's a few lines of code.
I admit, that this short introduction into promises was quite rough and it's also quite new to Objective-C developers, and may sound uncommon.
You can read a lot about promises in the JS community. There are one or three implementations in Objective-C. The actual implementation won't exceed a few hundred lines of code. It happens, that I'm the author of one of it:
RXPromise.
Take it with a grain of salt, I'm probably totally biased, and apparently all others ever dealt with Promises, too. ;)

Objective-C – Waiting for two async methods to complete

I'm calling four methods that I want to execute in synchronous order, the first two methods are synchronous, the last two methods are asynchronous (data fetching from URLs).
Pseudo-code:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
BOOL object3Synced = [object3 sync]; // Async method
BOOL object4Synced = [object4 sync]; // Async method
// Wait for object3 and object4 has finished and then hide activity indicator
}
How can I achieve this?
Use a barrier:
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
Submits a barrier block for asynchronous execution and returns immediately.
When the barrier block reaches the front of a private concurrent
queue, it is not executed immediately.
Instead, the queue waits until its currently executing blocks finish executing.
At that point, the
queue executes the barrier block by itself. Any blocks submitted after
the barrier block are not executed until the barrier block completes.
This example outputs 1 2 3 4 done although being asynchronous, it could be 1 2 4 3 done. Since I understand you want to handle an activity indicator, this shouldn't matter.
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
dispatch_queue_t queue = dispatch_queue_create("com.myqueue", 0);
dispatch_sync(queue, ^(){NSLog(#"1");} );
dispatch_sync(queue, ^(){NSLog(#"2");});
dispatch_async(queue, ^(){NSLog(#"3");});
dispatch_async(queue, ^(){NSLog(#"4");});
dispatch_barrier_sync(queue, ^(){NSLog(#"done");});
}
}
For other ways to test asynchronous code, see: https://stackoverflow.com/a/11179523/412916
Assuming you actually have some sort of way of knowing when the asynchronous methods are done, what you probably want is something like:
- (void)syncData {
// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method
_object3Synced = _object4Synced = NO;
[object3 syncWithCompletionHandler:
^{
_object3Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
[object4 syncWithCompletionHandler:
^{
_object4Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
}
- (void)considerHidingActivityIndicator
{
if(_object3Synced && _object4Synced)
{
// hide activity indicator, etc
}
}
You can make a subclass of UIActivityInidicator, add an activityCount property and implement these two additional methods:
- (void)incrementActivityCount
{
if(_activityCount == 0)
{
[self startAnimating];
}
_activityCount++;
}
- (void)decrementActivityCount
{
_activityCount--;
if(_activityCount <= 0)
{
_activityCount = 0;
[self stopAnimating];
}
}
Now whenever you start something that uses the activity counter call incrementActivityCount and in its completion block (or otherwise when it finishes) call decrementActivityCount. You can do other things if you want in these methods, the above is just a simple example which is probably sufficient in most cases (especially if you set hidesWhenStopped = YES).
You would need to launch the first Async method and use a completion block. In the completion block of the first async method, you would launch your second async method. Though this kind of makes using async methods irrelevant.

The most common and right pattern for performing synchronous tasks, asynchronous tasks to create a composite operation

I am rather new to iOS and Objective-C.
I am developing a project aiming to make a composition of complex (or "composite") operations as easy as possible: https://github.com/stanislaw/SACompositeOperations
I have four kinds of operations there: two single operations (sync and async) and two complex operations (cascaded and "transactional"). Single operations are used as "atoms" for complex operations, so I want to make them as good as possible in compliance with Objective-C best practices.
What I am interested in is: what code should I choose for these single operations?
By calling the first of two single operations "sync" I mean: run something probably asynchronous with completion handler and lock the flow waiting until it is done. "Async" means truly asynchronous operation - just run operation block in asynchronous fashion.
Here is the single operations code I currently use:
Sync operation
- (void)run:(syncOperationBlock)block {
self.semaphore = dispatch_semaphore_create(0);
block(self);
while (dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_NOW))
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}
- (void)finish {
dispatch_semaphore_signal(self.semaphore);
}
#end
Async operation
- (void)run:(asyncOperationBlock)block {
dispatch_queue_t queue = dispatch_queue_create("async_operation.queue", 0);
dispatch_async(queue, ^{
block(self);
});
}
I will be thankful, if someone can suggest any solutions for these single sync- and async- operations: more generic, more common, just better for the cases I've described
Shortly: what is the best code for forced-synchronous operation, for async operation?
Thanks.
My project did evolve significantly since I've asked this question.
From the structural point of view, I can't say much interesting about asynchronous operations: in my project they are all based on dispatch_async and the most valuable functionality is implemented with intensive usage of blocks (mainly: yielding operations themselves to the blocks they execute, allows to control a flow of these operations).
The more interesting thing to note here is the code I currently use for synchronous (or "forced-synchronous") operations - though their usage should be avoided in real apps, they are still applicable in unit tests: one example is a need to straighten the curly asynchronous flow of asynchronous net request to test its result in place, in the context of unit test case.
Though I am posting this as an answer to my non-specific question I would still really like to see any authoritative answer about whether my SASyncOperation is good enough for forced-sync operations (in the sense I've described it in this question) or maybe it could be improved more.
SASyncOperation as it currently written
Does not block main thread if it is run on main thread.
Does not produce excessive CPU polling as simple approaches with while(!completed){}; do.
This is the most important part of the code:
#import "SASyncOperation.h"
#interface SASyncOperation () {
BOOL _isOnMainThread;
dispatch_semaphore_t _semaphore;
}
#end
#implementation SASyncOperation
// …
- (void)start {
_semaphore = dispatch_semaphore_create(0);
_operation(self);
if (_finished) return;
if ((_isOnMainThread = [NSThread isMainThread])) {
while (dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_NOW)) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, [[NSDate distantFuture] timeIntervalSinceNow], NO);
}
} else {
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}
_finished = YES;
}
- (void)run:(^(void)(SASyncOperation *)block {
_operation = [block copy];
[self start];
}
- (void)finish {
_finished = YES;
dispatch_semaphore_signal(_semaphore);
if (_isOnMainThread) {
dispatch_async(dispatch_get_main_queue(), ^{
CFRunLoopStop(CFRunLoopGetMain());
});
}
}
// …
#end
This is how SASyncOperation should be used:
SASyncOperation *syncOperation = [[SASyncOperation alloc] init];
[syncOperation run:^(SASyncOperation *so) {
doSomeThingMultiQueuedPossiblyMultiblockedAndAsynchronous(^{
soOver = YES;
[so finish];
});
}]; // <- (*)
// (*) The flow will be stopped at this point waiting when 'so' operation will finish itself

Perform block inside a NSOperation

I have a method in some class which performs some task using a block. When I execute that method using NSInvocationOperation then control never goes to the block. I tried logging inside the block but that is never called actually. But if I simply call that method with instance of that class then everything works as expected.
Don’t blocks run inside NSOperation?
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:myClassObj selector:#selector(myClassMethod:) object:obj1];
[[AppDelegate sharedOpQueue] addOperation:op];
[op release];
- (void)myClassMethod:(id)obj
{
AnotherClass *otherClass = [[AnotherClass allco] init]
[otherClass fetchXMLWithCompletionHandler:^(WACloudURLRequest* request, xmlDocPtr doc, NSError* error)
{
if(error){
if([_delegate respondsToSelector:#selector(handleFail:)]){
[_delegate handleFail:error];
}
return;
}
if([_delegate respondsToSelector:#selector(doSomeAction)]){
[_delegate doSomeAction];
}
}];
}
- (void) fetchXMLWithCompletionHandler:(WAFetchXMLHandler)block
{
_xmlBlock = [block copy];
[NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(_xmlBlock) {
const char *baseURL = NULL;
const char *encoding = NULL;
xmlDocPtr doc = xmlReadMemory([_data bytes], (int)[_data length], baseURL, encoding, (XML_PARSE_NOCDATA | XML_PARSE_NOBLANKS));
NSError* error = [WAXMLHelper checkForError:doc];
if(error){
_xmlBlock(self, nil, error);
} else {
_xmlBlock(self, doc, nil);
}
xmlFreeDoc(doc);
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
if(_xmlBlock) {
_xmlBlock(self, nil, error);
}
}
You are performing your NSConnection asynchronously (which you don't need to do in an NSOperation because you should already be on a background thread).
After your call to fetchXMLWithCompletionHandler, your method ends. This signals that the NSOperation is finished and it gets released and it's thread gets either reused for something else or, more likely, released as well. This means that by the time you get your callbacks, your initial object doesn't exist anymore!
There are two solutions :
1) Use NSURLConnection synchronously. This will wait in your myClassMethod until it has got a response.
2) Learn about NSOperations's concurrent mode. I don't know if this will work with NSInvocationOperation though :( And it's fairly complicated compared to option (1).
I would use method (1) - you have already created a background thread to perform your operation in, why bother creating another one to do your connection request?
There are two ways of fixing your problem:
The easy way out
is — as Dean suggests — using +[NSURLConnection sendSynchronousRequest:returningResponse:error:], as you already are on a different thread. This has you covered — I'd say — 80-90% of the time, is really simple to implement and Just Works™.
The other way
is only slightly more complicated and has you covered for all the cases where the first method does not suffice — by visiting the root of your problem:
NSURLConnection works in conjunction with the runloop — and the threads managed by NSOperationQueue don't necessarily use (or even have!) an associated runloop.
While calling +[NSURLConnection connectionWithRequest:delegate:] will implicitly create a runloop, if needed, it does not cause the runloop to actually run!
This is your responsibility, when the NSOperationQueue you use is not the queue associated with the main thread.
To do so, change your implementation of fetchXMLWithCompletionHandler: to look similar to the following:
- (void)fetchXMLWithCompletionHandler:(WAFetchXMLHandler)block
{
self.xmlHandler = block; // Declare a #property for the block with the copy attribute set
self.mutableXMLData = [NSMutableData data]; // again, you should have a property for this...
self.currentConnection = [NSURLConnection connectionWithRequest:request delegate:self]; // having a #property for the connection allows you to cancel it, if needed.
self.connectionShouldBeRunning = YES; // ...and have a BOOL like this one, setting it to NO in connectionDidFinishLoad: and connection:didFailWithError:
NSRunLoop *loop = [NSRunLoop currentRunLoop];
NSDate *neverExpire = [NSDate distantFuture];
BOOL runLoopDidIterateRegularly = YES;
while( self.connectionShouldBeRunning && runLoopDidIterateRegularly ) {
runLoopDidIterateRegularly = [loop runMode:NSDefaultRunLoopMode beforeDate:neverExpire];
}
}
With these small changes, you're good to go. Bonus: this is really flexible and (eventually) reusable throughout all your code — if you move the XML-parsing out of that class and make your handler simply take an NSData, an NSError and (optionally) an NSURLResponse.
Since you probably don't want the clients of your loader to see and possibly mess with the properties I just suggested you should add, you can declare them in a class continuation.