Created
January 13, 2020 10:06
-
-
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
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 | |
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 = [] | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👍 :)