func backgroundExecutable(f: (() -> Void) -> Void) -> (() -> Void)
This is madness and it takes a number of mental gymnastics to figure out what is going on here.
This method takes, as its only (and poorly named) argument, a closure which returns void and takes, as its single argument, a closure which returns void from taking no arguments. Then this method returns a closure which takes no arguments and returns void.
Even writing it out in plain-English, it's hard to understand what's actually going on. And I'm left scratching my head trying to figure out why we even need a closure which takes a closure as its argument.
The major problem here is that we're using this closure's closure argument to pass the call to endBackgroundTask()
, a method which must be called, or we risk the OS killing our app.
Your class is attempting to provide a convenient wrapper to handling the background means for executing code while your application is in the background. But your class hasn't made things any more convenient then what they already are. It only makes them more nested and complicated.
So let's look at execute
for a second, shall we?
func execute() {
let application = UIApplication.sharedApplication()
identifier = application.beginBackgroundTaskWithExpirationHandler {
application.endBackgroundTask(self.identifier)
}
f(endBackgroundTask)
}
The crux of this is that endBackgroundTask
, another method of this class (which should perhaps be private
) is passed in as the closure the the user's background executing closure. If they don't call the closure that's passed in (and call it only as the last thing their closure does), there will be unintended problems going on here.
But why do that? We can instead do this:
f()
endBackgroundTask()
That's a step in the right direction. We're no longer relying on the caller to end the background task.
But there's another problem here. What if we call execute
multiple times and on multiple threads? The identifier
will be different each time we call execute
, and each time it overwrites the previous identifier. So all the previous background tasks can't be stopped, and so the OS will eventually kill our app for running indefinitely in the background.
Instead, we need our endBackgroundTask
method to take a string argument... the identifier of the task we're stopping. And we need to not rely on a string variable for our class.
So, it needs to look more like this:
f()
endBackgroundTask(identifier)
At this point, I'm not entirely certain the point of the class at all when a single method with just a handful of lines can manage it:
func backgroundExecute(worker: () -> Void) -> Void {
let application = UIApplication.sharedApplication()
identifier = application.beginBackgroundTaskWithExpirationHandler {
// you can't call endBackgroundTask here, and you don't need to
// here you should put code to handle the task running out of time before it is complete
}
worker()
application.endBackgroundTask(identifier)
}