I have a long series of events that needs to happen in my Objective-C code. Lets say I have 6 things - thingA, thingB, thingC, thingD, thingE and thingF. thingB and thingD return a BOOL. If thingB is NO, then thingC doesn't need to be called. If thingD is NO, then thingE doesn't need to be called.
- (void)doThings:(void(^)())completion {
[self thingA: ^{
[self thingB: ^(BOOL success) {
if (success) {
[self thingC: ^{
[self thingD: ^(BOOL success) {
if (thingD) {
[self thingE: ^{
[self thingF];
completion();
}];
return;
}
[self thingF];
completion();
}];
}];
return;
}
[self thingD: ^(BOOL success) {
if (success) {
[self thingE: ^{
[self thingF];
completion();
}];
return;
}
[self thingF];
completion();
}];
}];
}];
}
This can quickly become unwieldy. You can take the things that have different outcomes but lead back into the loop, and make them into new methods, as such:
- (void)doThings:(void(^)())completion {
[self thingA: ^{
[self attemptThingB: ^{
[self attemptThingD: ^{
[self thingF];
completion();
}]
}];
}]
}
- (void)attemptThingB:(void(^)())completion {
[self thingB: ^(BOOL success) {
if (success) {
[self thingC: {
completion();
}];
return;
}
completion();
}];
}
- (void)attemptThingD:(void(^)())completion {
[self thingD: ^(BOOL success) {
if (success) {
[self thingE: ^{
completion();
}];
return;
}
completion();
}];
}
This reduces code duplication, but is still messy and difficult to keep track of. It even results in methods with awkward names, which are really just helper methods to this particular case.
There must be a better way. Something that looks a lot like synchronous coding, but is asynchronous. The above code is difficult to read, which makes it dangerous if I ever want to add something new to the flow.
Suggestions of a better solution? Something like this?
- (void)doThings {
[self thingA];
BOOL thingBSuccess = [self thingB];
if (thingBSuccess == YES) {
[self thingC];
}
BOOL thingDSuccess = [self thingD];
if (thingDSuccess == YES) {
[self thingE];
}
[self thingF];
return;
}
The immediately evident problem with that proposed solution is that the completion handler can pass out multiple objects, whereas the return value of a block can only handle 1 object. But something with a format similar to this? It's so much cleaner and easy to maintain.