According to docs, .focusedObject()
usage should be moved to .focusedValue()
when migrating to @Observable
, but there is no .focusedSceneValue()
overload that accepts Observable like with .focusedValue()
. So how are we supposed migrate .focusedSceneObject()
to @Observable
?
How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here
How to use `.focusedSceneObject()` with @Observable?
The migration from .focusedSceneObject()
to @Observable
in SwiftUI can be achieved by using a @State
property to store the focused value and then binding the focused
property of the view to this @State
property. Here's how you can migrate from .focusedSceneObject()
to @Observable
:
-
Define an
@Observable
Property:Create an
@Observable
property that will store the focused value. This property can be of any appropriate data type, such as aString
or a custom struct. For example:@Observable var focusedValue: String = ""
-
Bind
focused
to the@Observable
Property:Instead of using
.focusedSceneObject()
, you can bind thefocused
property of a view to your@Observable
property using the$
syntax. This allows you to set and get the focused value.For example, if you were using
.focusedSceneObject()
like this:.focusedSceneObject(\.focusedValue)
You can migrate it to
@Observable
like this:.focused($focusedValue)
This binding connects the view's focus state to the
focusedValue
property. -
Update Usage of the Focused Value:
Wherever you were using
.focusedSceneObject(\.focusedValue)
, you can now use thefocusedValue
property directly.For example, if you had a Text view displaying the focused value:
Text("Focused Value: \(focusedValue)")
This code will still work with the
focusedValue
property defined in step 1.
By following these steps, you can migrate from .focusedSceneObject()
to @Observable
while maintaining the functionality of managing the focused value in your SwiftUI view.
I'm just migrating some ObservedObjects
to Observable
and ran into this problem with a Commands
menu with a FocusedObject
dependency. I want some entries in the menu to be enabled and to act on state from the Observable
object.
What finally worked for me (so far) is using a FocusedValues
extension. I couldn't get this to work without the key path API, despite what the documentation says, and there doesn't appear to be a single example on the Internet.
struct MyFocusedObservableStateValue: FocusedValueKey {
typealias Value = MyObservableStateType
}
extension FocusedValues {
var myObservableState: MyFocusedObservableStateValue.Value? {
get { self[MyFocusedObservableStateValue.self] }
set { self[MyFocusedObservableStateValue.self] = newValue }
}
}
struct ItemActionsCommandMenu: Commands {
@FocusedValue(\.myObservableState) var myObservableState
var body: some Commands {
CommandMenu("Menu Name") {
// use myObservableState as needed (Note: It's optional)
Button("Action") {
}
.disabled(...)
}
}
}
Elsewhere in App:
myContentView
.focusedSceneValue(\.myObservableState, myObservableState)