Skip to content

Instantly share code, notes, and snippets.

@juliengdt
Last active November 19, 2020 09:10
Show Gist options
  • Save juliengdt/4e27cd1bf4fe3db70144cbdffd86af86 to your computer and use it in GitHub Desktop.
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
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