Skip to content

Instantly share code, notes, and snippets.

@jnordberg
Last active December 2, 2019 18:11
Show Gist options
  • Save jnordberg/0ef4205efdafeb7bb6fb0f1a0d7ac1d0 to your computer and use it in GitHub Desktop.
Save jnordberg/0ef4205efdafeb7bb6fb0f1a0d7ac1d0 to your computer and use it in GitHub Desktop.
import Combine
final class ObservableOptional<Wrapped: ObservableObject>: ObservableObject {
let objectWillChange = ObservableObjectPublisher()
var value: Wrapped? {
willSet {
objectWillChange.send()
updateSubscription(newValue)
}
}
private var subscriber: AnyCancellable?
init(_ value: Wrapped? = nil) {
self.value = value
updateSubscription(value)
}
private func updateSubscription(_ value: Wrapped?) {
subscriber?.cancel()
if let publisher = value?.objectWillChange {
subscriber = publisher.sink { [weak self] _ in
self?.objectWillChange.send()
}
}
}
}
// MARK: Example
import SwiftUI
class ThingsResult: ObservableObject {
let initial: String
@Published var later: String? = nil
init(_ initial: String) {
self.initial = initial
}
}
func doThings() -> ThingsResult {
let rv = ThingsResult("some stuff")
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { [weak rv] _ in
rv?.later = "more stuff"
}
return rv
}
class ResultsProxy: ObservableObject {
var objectWillChange = ObservableObjectPublisher()
var value: ThingsResult? {
willSet {
objectWillChange.send()
if let childPublisher = newValue?.objectWillChange {
objectWillChange = childPublisher
}
}
}
}
struct ContentView: View {
@ObservedObject var result = ObservableOptional<ThingsResult>()
var body: some View {
VStack {
if self.result.value != nil {
Text("Result").bold()
Text(self.result.value!.initial)
Text(self.result.value!.later ?? "waiting for more stuff...")
} else {
Button(action: {
self.result.value = doThings()
}) {
Text("Do things")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment