Last active
September 25, 2021 09:30
-
-
Save tarunon/494d58245fe47be79465bd6f14d4183a to your computer and use it in GitHub Desktop.
Swift Task Extension for slim AsyncSequence access.
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 UIKit | |
class Base: UIViewController { | |
func mySomeAsyncSequence() -> AsyncStream<String> { | |
fatalError() | |
} | |
func use(_ value: String) { | |
print(value) | |
} | |
} | |
/** | |
* Today we got async/await and AsyncSequence, we can write extream concurrency programming, but... | |
* AsyncSequence's memory management is very lazy... | |
*/ | |
class Common: Base { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// start boilerplate 😭 | |
Task { [weak self] in | |
guard let sequence = self?.mySomeAsyncSequence() else { return } | |
for await element in sequence { | |
guard let self = self else { return } | |
self.use(element) | |
} | |
} | |
// end boilerplate 😭 | |
} | |
} | |
/** | |
* Ok, create Swift Concurrency support classes. | |
* AsyncSequence, show me your true power! | |
*/ | |
class TaskContext<T: AnyObject> { | |
private weak var weakValue: T? | |
var value: T { | |
get throws { | |
guard let value = weakValue else { throw CancellationError() } | |
return value | |
} | |
} | |
init(weakValue: T?) { | |
self.weakValue = weakValue | |
} | |
} | |
extension Task where Failure == Error { | |
@discardableResult | |
init<T>(priority: TaskPriority? = nil, context: T, operation: @Sendable @escaping (TaskContext<T>) async throws -> Success) { | |
let taskContext = TaskContext(weakValue: context) | |
self.init(priority: priority, operation: { | |
try await operation(taskContext) | |
}) | |
} | |
} | |
/** | |
* Try it out! | |
*/ | |
class TunedUp: Base { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// begin code ✨ | |
Task(context: self) { context in | |
for await element in try context.value.mySomeAsyncSequence() { | |
try context.value.use(element) | |
} | |
} | |
// end code ✨ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just define
tryUnwrapped
operator on Optional extension can be more simple? 😭