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?
^blockName: Always remember that the block name is preceded by the ^ symbol. The block name can be any string you like, just like you name any other variable or method. Remember that both the ^ and the block name are enclosed in parentheses ().
__block is a storage qualifier that can be used in two ways: Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).
In order to run Objective-C program on windows, we need to install MinGW and GNUStep Core. Both are available at https://www.gnu.org/software/gnustep/windows/installer.html. First, we need to install the MSYS/MinGW System package. Then, we need to install the GNUstep Core package.
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With