Skip to content

Instantly share code, notes, and snippets.

@chockenberry
Created April 12, 2024 17:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chockenberry/c5d75a1db4f31441990a3f1bd995c7b5 to your computer and use it in GitHub Desktop.
Save chockenberry/c5d75a1db4f31441990a3f1bd995c7b5 to your computer and use it in GitHub Desktop.
Optional Bindable
//
// ContentView.swift
// BindableOptional
//
// Created by Craig Hockenberry on 4/12/24.
//
import SwiftUI
@Observable
class Whatever {
var number: Int = 0
}
struct OtherView: View {
@Binding var whatever: Whatever
// This allows the view to work with @Bindable, but breaks the traditional $ binding
//@Bindable var whatever: Whatever
var body: some View {
Button("Do Whatever") {
whatever.number += 1
}
.buttonStyle(.borderedProminent)
}
}
struct ContentView: View {
@State private var optionalWhatever: Whatever?
@State private var whatever = Whatever()
var body: some View {
#if DEBUG
let _ = Self._printChanges()
#endif
VStack {
if let whateverInstance = optionalWhatever {
Text("Optional Whatever = \(whateverInstance.number)")
@Bindable var whateverBinding = whateverInstance
// Cannot convert value of type 'Bindable<Whatever>' to expected argument type 'Binding<Whatever>'
//OtherView(whatever: $whateverBinding)
}
else {
Text("No Optional Whatever")
Button("Make Optional Whatever") {
optionalWhatever = Whatever()
optionalWhatever!.number = 999
}
.buttonStyle(.borderedProminent)
}
}
.padding()
VStack {
Text("Whatever = \(whatever.number)")
OtherView(whatever: $whatever)
}
.padding()
}
}
#Preview {
ContentView()
}
@chockenberry
Copy link
Author

The problem here is that you need to use properties of the Observable, not the Observable itself:

struct OtherViewNumber: View {
	@Binding var whateverNumber: Double
	
	var body: some View {
		Button("Do Whatever Number") {
			whateverNumber += 1
		}
		.buttonStyle(.borderedProminent)
	}
}

The view can then be used in both contexts:

	@Bindable var whateverBindable = whateverInstance
	OtherViewNumber(whateverNumber: $whateverBindable.number)

and:

	OtherViewNumber(whateverNumber: $whatever.number)

It's a subtle distinction, but the dynamic member lookup for both Bindable and Binding makes it work.

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