Skip to content

Instantly share code, notes, and snippets.

@nerdsupremacist
Created January 13, 2020 10:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nerdsupremacist/afb9c41fcfb60c768336f3617eb6148e to your computer and use it in GitHub Desktop.
Save nerdsupremacist/afb9c41fcfb60c768336f3617eb6148e to your computer and use it in GitHub Desktop.
Set up bindings for Combine Publishers within the lifecycle of a SwiftUI View
import Foundation
import Combine
import SwiftUI
extension View {
func binding(@CancellableBuilder bindings: @escaping () -> AnyCancellable) -> some View {
return BindingView(content: AnyView(self), bindings: bindings)
}
}
@_functionBuilder
enum CancellableBuilder {
static func buildBlock(_ cancellable: Cancellable) -> AnyCancellable {
return cancellable.eraseType()
}
static func buildBlock(_ cancellables: Cancellable...) -> AnyCancellable {
return cancellables.map { $0.eraseType() }.eraseType()
}
}
extension Array: Cancellable where Element: Cancellable {
public func cancel() {
for element in self {
element.cancel()
}
}
}
extension Cancellable {
fileprivate func eraseType() -> AnyCancellable {
return AnyCancellable(self)
}
}
private struct BindingView: View {
let content: AnyView
let bindings: () -> AnyCancellable
@State
private var cancellableSet: Set<AnyCancellable> = []
var body: some View {
content
.onAppear {
guard self.cancellableSet.isEmpty else { return }
self.bindings().store(in: &self.cancellableSet)
}
.onDisappear {
self.cancellableSet = []
}
}
}
@adam-zethraeus
Copy link

👍 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment