Last active
December 12, 2019 17:54
-
-
Save JoeMatt/e2448c43af386ba743529c3c895750a6 to your computer and use it in GitHub Desktop.
Example of guarantee of parallel execution and single firing of completion block
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)enableFirebaseSyncCompletion:(void(^)(void))completion { | |
// ------- This is the setup of the groups, factories etc ----------- | |
// Create a new top level group, __block so we can pass it into child groups | |
__block dispatch_group_t topGroup = dispatch_group_create(); | |
// Type-defs make things easier to read | |
typedef void (^ReturnedBlock)(void); | |
typedef void (^ParamBlock)(ReturnedBlock); | |
// Make a new block called makeCompletion, that captures topGroup in it's scope | |
// It returns a block that calls leave on topGroup when it's inner calls are done | |
ReturnedBlock (^makeCompletion)() = ^ReturnedBlock(void){ | |
// Optional: To make this more robust we could make the topGroup a parameter | |
// by replacig the void here `^ReturnedBlock(void)` with `^ReturnedBlock(dispatch_group_t)` | |
// Make new inner group | |
__block dispatch_group_t innerGroup = dispatch_group_create(); | |
// Enter innerGroup once | |
dispatch_group_enter( innerGroup ); | |
ReturnedBlock retBlock = ^void(void){ | |
// Block that is returned, leaves the inner group. | |
// It's ok if this block gets called multiple times, because the | |
// group notify will fire on the first call | |
dispatch_group_leave( innerGroup ); | |
}; | |
// After the returned block is called the first time, | |
// it will trigger this to execute... | |
dispatch_group_notify(innerGroup, dispatch_get_main_queue(), ^{ | |
// .. which leaves the topGroup 1 time, to match our 1 entry | |
// at the top of this makeCompletion | |
dispatch_group_leave( topGroup ); | |
}); | |
// Return the block that will trigger the innerGroup -> outerGroup leave sequence when called by whomever we give it too | |
return retBlock; | |
}; | |
// Convenice block that handles calling the makeCompletion for us | |
void (^wrap)(ParamBlock) = ^(ParamBlock param){ | |
// Make a new completion handler, | |
// remember, calling makeCompletion() makes a new first class function | |
// which it's own innerGroup, but captures the __block reference to the main topGroup | |
ReturnedBlock newCompletion = makeCompletion(); | |
// This is where we actaully enter the top group | |
dispatch_group_enter(topGroup); | |
// call the passed in code block, | |
// we're also forwarding along the completion handlder that | |
// needs to be called at some point. | |
param(newCompletion); | |
}; | |
// ----- This is where you're making your async calls. wrap() is a conveneince, | |
// ----- you could call makeCompletion() yourself and pass the returned black to wherever | |
// 1. example usage | |
wrap( ^(ReturnedBlock wrapCompletion){ | |
// NOTE: completion can be called multiple times, but needs to be called at least once! | |
// You could wrap a timer here to call it after a certain time out if you wanted | |
[self someAsyncCall:wrapCompletion]; | |
}); | |
// 2. example usage | |
wrap( ^(ReturnedBlock wrapCompletion){ | |
// another call example.. | |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
// ... DO some work on the background | |
// ... | |
wrapCompletion(); | |
}); | |
}); | |
// 3. example usage | |
ReturnedBlock anotherCompletion = makeCompletion(); | |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
// ... Do some other work on the background | |
// ... ,, call the completion though! | |
anotherCompletion(); | |
}); | |
// ---- Bottom of call ---- | |
// wait for topGroup to finish, call the passed in completion when it does | |
// This is async so it will return this function after | |
dispatch_group_notify(topGroup, dispatch_get_main_queue(), completion); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment