Last active
November 19, 2020 09:10
-
-
Save juliengdt/4e27cd1bf4fe3db70144cbdffd86af86 to your computer and use it in GitHub Desktop.
Do ! Or how to 'clean up' code when using `Dispatch.main`+ weak pointer
This file contains 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
import Foundation | |
/// #Do class - Or how to transform DispatchQueue-escaping-weakable stuff on pointer into a more readable usage | |
/// TL;DR - Usage | |
// In ViewModel/Interactor | |
Do.bg(on: self) { this in | |
this.doSomeWSCalls() | |
} | |
// In View(Controller | |
Do.ui(on: self) { this in | |
this.reloadView() | |
} | |
/// A nano class which help developer avoid messy code with DispatchQueue and `self` weaked pointer | |
final class Do { | |
typealias DoClosure<T> = ((_:T)->()) // just because it's horrible to read | |
private init() {} | |
/// Do it in background thread | |
static func bg<T: AnyObject>(on object: T, closure: @escaping DoClosure<T>) { | |
weak var _object = object | |
DispatchQueue.global(qos: .background).async { | |
guard let __obj = _object else { return } | |
closure(__obj) | |
} | |
} | |
/// Do it in main thread | |
static func ui<T: AnyObject>(on object: T, closure: @escaping DoClosure<T>) { | |
weak var _object = object | |
DispatchQueue.main.async { | |
guard let __obj = _object else { return } | |
closure(__obj) | |
} | |
} | |
} | |
/// ## From this ... | |
class MyClass { | |
var string: String = "Oh, Hello !" | |
func doSomethingOnScreen() { | |
DispatchQueue.main.async { [weak self] in | |
print(self?.string ?? "borken pointer") | |
} | |
} | |
func doSomethingInBackground() { | |
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { [weak self] in | |
self?.string = "Oh, Hello from the background !" | |
} | |
} | |
} | |
/// ## ... to this | |
class MyBetterClass { | |
var string: String = "Oh, Hello !" | |
func doSomethingOnScreen() { | |
Do.ui(on: self) { this in | |
print(this.string) | |
} | |
} | |
func doSomethingInBackground() { | |
Do.bg(on: self) { this in | |
this.string = "Oh, Hello from the background ! (But better π)" | |
} | |
} | |
} | |
/// Usage | |
class _MyClass { | |
var string: String = "Oh, Hello !" | |
func doSomethingOnScreen() { | |
DispatchQueue.main.async { [weak self] in | |
Thread.printCurrentDescription() | |
print(self?.string ?? "borken pointer") | |
print("Done things in the background.") | |
} | |
} | |
func doSomethingInBackground() { | |
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { [weak self] in | |
Thread.printCurrentDescription() | |
self?.string = "Oh, Hello from the background !" | |
print("Done things in the background.") | |
} | |
} | |
} | |
class _MyBetterClass { | |
var string: String = "Oh, Hello !" | |
func doSomethingOnScreen() { | |
Do.ui(on: self) { this in | |
Thread.printCurrentDescription() | |
print(this.string) | |
print("Done things in the background. (But better π)") | |
} | |
} | |
func doSomethingInBackground() { | |
Do.bg(on: self) { this in | |
Thread.printCurrentDescription() | |
this.string = "Oh, Hello from the background ! (But better π)" | |
} | |
} | |
} | |
// β οΈ -- debug print are biased (their order) due to print latency ... | |
let boringClass = _MyClass() | |
boringClass.doSomethingInBackground() | |
do { | |
sleep(1) | |
} | |
boringClass.doSomethingOnScreen() | |
do { | |
sleep(2) | |
} | |
let betterClass = _MyBetterClass() | |
betterClass.doSomethingInBackground() | |
do { | |
sleep(1) | |
} | |
betterClass.doSomethingOnScreen() | |
/// Just a helper extension π | |
extension Thread { | |
class func printCurrentDescription() { | |
print("\rβ‘οΈ: \(Thread.current)\r" + "π: \(OperationQueue.current?.underlyingQueue?.label ?? "None")\r") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment