I need simple ways to make a class that I can pass and call a callback function using Swift 3.0
I don't like to use anything like a Notification Centers or Selectors with # before them. I'm picky and I also don't like to type that much.
Example:
func setCallback(function:Callback){
self.callback = function
}
func callCallback(){
self.callback()
}
Let's imagine you have some complex task and you want to supply a callback to be called when the task is done:
class ComplexTaskManager {
var completionHandler: (() -> Void)?
func performSomeComplexTask() {
...
// when done, call the completion handler
completionHandler?()
// if this was a one-time completion handler, you'd `nil` it; it helps protect against strong reference cycles; otherwise comment the next line
completionHandler = nil
}
}
So, you'd use it like:
let manager = ComplexTaskManager()
manager.completionHandler = {
// this is what I want to do when the task is done
}
manager.performSomeComplexTask()
Now, I'm imagining that we're dealing with some time consuming asynchronous task for which you want to call the callback when it's done. But there are other, similar patterns (e.g. perhaps you're iterating through some model object and you want to call your callback for every instance within that object), but the idea is the same as above.
If you have a strong reference cycle, you can fix that with weak references (e.g. supply [weak self]
or [unowned self]
to the closure). For example, imagine:
class ViewController {
let manager = ComplexTaskManager()
@IBOutlet weak var statusLabel: UILabel!
override viewDidLoad() {
super.viewDidLoad()
statusLabel.text = "Starting complex task"
manager.completionHandler = { [weak self] in
self?.statusLabel.text = "Done"
}
manager.performSomeComplexTask()
}
}
But you only need to do this if there is a strong reference cycle (e.g. the view controller is keeping strong reference to the manager and because of the presence of self
inside the closure, the manager is keeping a strong reference back to the view controller). If either of these are local references rather than properties, though, there is no strong reference cycle to break.
Frankly, the more common pattern for a closure that will be called once per task is to supply it as a parameter of the method. For example:
class ComplexTaskManager {
func performSomeComplexTask(completionHandler: () -> Void) {
...
// when done, call the completion handler
completionHandler()
}
}
So, you'd use it like:
let manager = ComplexTaskManager()
manager.performSomeComplexTask() {
// this is what I want to do when the task is done
}
The beauty of this approach is that it's not only simpler, but avoids the risk of strong reference cycles.
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