I have some code which requires the use of blocks. The block fetches a number of data items from a web service, and then possibly needs to fetch more, and then more again after that, then returns all of the data items once it has all required. I'm unsure how to put this into code. Here's an example of what I mean:
NSMutableArray *array = [[NSMutableArray alloc] init];
[webService getLatestItemsWithCount:50 completion:^(NSArray *objects) {
//Some code to deal with these items.
if (moreItemsNeeded == YES) {
//I now need it to loop this block until I'm done
}
}];
How can I get this to work?
EDIT:
Ok, this is what i'm working with - it's the Evernote API. It should be a better example of what I need:
[noteStore findNotesMetadataWithFilter:filter
offset:0
maxNotes:100
resultSpec:resultSpec
success:^(EDAMNotesMetadataList *metadataList) {
for (EDAMNoteMetadata *metadata in metadataList.notes) {
NSDate *timestamp = [NSDate endateFromEDAMTimestamp:metadata.updated];
if (timestamp.timeIntervalSince1970 > date.timeIntervalSince1970) {
[array addObject:metadata];
}
else {
arrayComplete = YES;
}
}
//I need it to loop this code, increasing the offset, until the array is complete.
}failure:^(NSError *error) {
NSLog(@"Failure: %@", error);
}];
You should create a variable that references the block to make possible the recursive invocation. It must be noted that at the moment that you assign the block, it is still nil, so if you call it inside the block itself (aka recursively), you'll get a crash while trying to execute a nil block. So the block should have a *__block* storage:
The block in your specific case is "translated" as this one:
Then you can normally call that method passing myBlock as argument.
About retain cycles
To avoid a retain cycle, you should set to nil the pointer to the block when the recursion finishes.
This is (as far as I've been able to figure out) - sort of an annoying connundrum - and one of blocks' few shortcomings... The following is the go-to archetype I refer to if I REALLY wanna make sure I'm being safe about it..
I prefer to use the fixed-point combinator structure to write block recursion. This way I don't have to mess with __block variables or risk a retain cycle when I forget to set the block to nil at the end of the recursion. All credit for this goes to Mike Ash who shared this code snippet.
Here's my version of his code (which I placed in a globally shared file so I can access this function from anywhere):
I know this looks super weird and confusing... but it's not too bad once you understand it. Here's what a simple recursive block might look like:
When you call
recursiveBlockVehicle
, you're passing a block that contains your code.recursiveBlockVehicle
's job is take this block that you passed and do three things:recursiveBlockVehicle
and pass that resultant as the parameter to the blockNow, inside your block's code, if you were to call the special
recurse
block parameter, you're in turn calling your own block all over again (achieving recursion). The nice thing about this strategy is that the memory management is fairly straight-forward. The use of parameters to pass your own code back to yourself reduces the risk of retain cycles. I use this method instead of defining a __block variable of my code because I'm afraid I might forget to set the __block variable to nil at the end of a recursion and result in a nasty retain cycle.With that in mind, here's how I would implement your function:
Again, note that you're not calling
callback
(the block object) inside of the block itself. The reason why is because the block is passing itself as a parameterrecurse
and executingrecurse
is how you achieve recursion.Also, (in case you've actually read this far and wanted to see more), here's a wikipedia page on FPC: http://en.wikipedia.org/wiki/Fixed-point_combinator
Lastly, I have not personally tested the retain cycle issue of a __block variable. However, Rob Mayoff did a fantastic analysis on the issue: https://stackoverflow.com/a/13091475/588253
Your code will be simpler to understand and less prone to leaking the block if you don't make the block recursive. Instead, wrap it in a method, and make the block call the method if it needs to keep searching.
This example is based on the code in your question:
With this design, you don't need to declare a reference to the block with an inscrutable type signature, and you don't have to worry about the block leaking because it references itself.
In this design, each call to the method creates a new block. The block references
self
, and (I assume)self
referencesnoteStore
, andnoteStore
references the block, so there is a retain cycle. But when the block finishes executing,noteStore
releases the block, breaking the retain cycle.