0

I'm trying to create an CoreData Entity observer:

@FetchRequest(sortDescriptors: []) var todoResult: FetchedResults<Todo>
    
    init() {
        todoResult.publisher.sink { _ in
            print("sink")
        } receiveValue: { todos in
            print("recoved todos")
        }.store(in: &cancellables)
}

But I'm getting this error:

Accessing StateObject's object without being installed on a View. This will create a new instance each time.

enter image description here

Any of you knows why I'm getting this error since I'm not creating this instance in a model? or if you know a work around this error. I'll really appreciated.

user2924482
  • 8,380
  • 23
  • 89
  • 173
  • Why are you trying to set a publisher to a `CoreData Entity`which is already an `ObservableObject`? That is the root of your error message. – Yrb Apr 01 '22 at 01:20
  • The behavior of FetchRequest is the same as State and StateObject, their internal are absent at initialisation phase and become available only inside body. To do what you want you can instantiate FetchRequest manually, like in https://stackoverflow.com/a/60761630/12299030 or in https://stackoverflow.com/a/59169794/12299030. Alternate is to create subview in body with injected todoResult, so todoResult will be already fetched and valid in that subview init. – Asperi Apr 01 '22 at 06:19
  • All CoreData objects are `ObservableObject`s, just wrap each `Todo` in `@ObservedObject` in the SwiftUI `View` that needs/makes the changes. BTW it looks like you are trying to use `@FetchRequest` in a class` use `NSFetchRequest` or `NSFetchedResultsController`. – lorem ipsum Apr 03 '22 at 22:54

1 Answers1

1

You have to use @FetchRequest inside a View struct.

The reason for the error that @StateObject must also be used inside a View struct is because the FetchRequest struct declares an @StateObject inside it, which is the delegate for the NSFetchedResultsController it uses.

In SwiftUI these dynamic properties/property wrappers give reference type semantics to the View struct value types so you don't need to use actual objects. SwiftUI calls update on these dynamic properties before body is run, which is how FetchRequest can retrieve the managed object context from the environment.

Also FYI when we do create an ObservableObject it's usually to hold our model struct array. If we use Combine inside one then we never use sink or cancellables, instead we assign the end of the pipeline to an @Published.

malhal
  • 26,330
  • 7
  • 115
  • 133
  • I add it `@Published internal var todo:[Todo] = []` and this `todoResult.publisher.assign(to: \.todo, on: self).store(in: &cancellables)` in the init but I'm getting this error `Key path value type '[Todo]' cannot be converted to contextual type 'Publishers.Sequence, Never>.Output' (aka 'Todo')` – user2924482 Apr 01 '22 at 16:45