Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import UIKit
import Combine
public extension Task {
/// Keep a reference to a task that can be cancelled.
func store(in set: inout Set<AnyCancellable>) {
set.insert(AnyCancellable {
self.cancel()
})
}
}
// Options A: automatically attach tasks to an object using associated objects
// on deinit AnyCancellable will be released and cancel the task
private let tasksKey = UnsafeRawPointer(UnsafeMutablePointer<UInt8>.allocate(capacity: 1))
public extension NSObject {
func task(priority: TaskPriority = .userInitiated, _ action: @escaping @Sendable () async -> Void) {
let task = Task(priority: priority, operation: action)
var tasks = objc_getAssociatedObject(self, tasksKey) as? Set<AnyCancellable> ?? []
task.store(in: &tasks)
objc_setAssociatedObject(self, tasksKey, tasks, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
class AViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
task {
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
}
}
// Option B: more explicitly store the tasks
class BViewController: UIViewController {
private var observers: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
Task {
try await Task.sleep(nanoseconds: 1_000_000_000)
}
.store(in: &observers)
}
}
// Option C: don't worry about it
class CViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// task will never be cancelled, but maybe that's fine
Task {
try await Task.sleep(nanoseconds: 1_000_000_000)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment