Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support @Observable macro #120

Closed
emadhegab opened this issue Jun 18, 2023 · 5 comments
Closed

Support @Observable macro #120

emadhegab opened this issue Jun 18, 2023 · 5 comments

Comments

@emadhegab
Copy link

in a model where i use @observable macro ,

@Observable
class SplashScreenViewModel {
    var presented: Bool = false

    @Injected(\.loginService) private var loginService: LoginServicing

i get 2 errors at the Injected vars

@observable requires property 'loginService' to have an initial value (from macro 'Observable')
Property wrapper cannot be applied to a computed property

@hmlongco
Copy link
Owner

hmlongco commented Jun 18, 2023

This is an issue with @observable.

"In the current implementation, the @observable macro requires that all stored properties have a default value. This helps observable types rely on definitive initialization, use the implicitly generated initializers, and define additional initializers in extensions."

You should, however, be able to get past the issue by doing something like...

    @ObservationIgnored @Injected(\.loginService) private var loginService: LoginServicing

See: https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro

Also keep in mind that if you use @observable your application can only run on iOS 17 and higher.

@hmlongco hmlongco pinned this issue Jun 19, 2023
@hmlongco hmlongco closed this as completed Jul 8, 2023
@joeljfischer
Copy link

joeljfischer commented Oct 28, 2023

I did figure this out, even before seeing this, but I'm seeing a new issue that I wasn't having with ObservableObject. My SwiftUI previews where I inject a preview object like:

struct WeatherAgeFooterView_Previews: PreviewProvider {
    static var previews: some View {
        let _ = Container.shared.weatherManager.register { WeatherManagerPreview() }

        WeatherAgeFooterView()
    }
}

is no longer working. In all my previews, I now get errors because they are running the Impl objects in my ViewModels instead of the preview objects I'm registering. This doesn't happen if I switch back to ObservableObject (which I really don't want to do because of the performance benefits to @Observable).

EDIT: I'd also be interested in a documentation section on how to get Factory injection like the above working with #Preview...if that's even possible.

@hmlongco
Copy link
Owner

I think your problem is elsewhere, as the following works...

import Factory
#if canImport(Observation)
import Observation
#endif
import SwiftUI

@available(iOS 17, *)
protocol ObservationServiceType: AnyObject {
    var name: String { get set }
}

@available(iOS 17, *)
@Observable
class ObservationService: ObservationServiceType {
    var name: String = "ObservationService"
}

@available(iOS 17, *)
@Observable
class MockObservationService: ObservationServiceType {
    var name: String = "MockObservationService"
}

@available(iOS 17, *)
extension Container {
    var observableService: Factory<ObservationServiceType> {
        self { ObservationService() }
    }
}

@available(iOS 17, *)
struct ObservableView: View {
    @Injected(\.observableService) var observableService
    var body: some View {
        HStack {
            Text(observableService.name)
            Spacer()
            Button("Mutate") {
                observableService.name += " *"
            }
        }
        .padding()
    }
}

@available(iOS 17, *)
#Preview {
    let _ = Container.shared.observableService.register { MockObservationService() }
    return ObservableView()
}

@hmlongco hmlongco reopened this Oct 28, 2023
@joeljfischer
Copy link

Okay, I tested this myself, and you're correct, it works. I have no idea why my previews are now using the default Impl versions and not preview versions of my services, but it doesn't appear to be what I thought it was.

@cneuwirt
Copy link

cneuwirt commented Jan 6, 2024

Are there any plans to support @bindable with @injected wrapper so bindings are available for use in Publisher Combinators

Initial comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants