Reputation: 3398
I have a Core Data Entity Entry
with a relationship to another Entity DataField
:
class Entry: NSManagedObject {
//[...]
@NSManaged public var stringFields: NSSet?
}
Because in most cases working with an NSSet?
isn't practical, Entry
has another variable:
var dataFields: [DataField] {
let arr = stringFields?.allObjects as! [DataField]
return arr.sorted(by: { $0.order < $1.order })
}
DataField
looks like this:
class DataField: NSManagedObject {
//[...]
@NSManaged var value: String
}
And EntryStore
is my wrapper around the whole thing:
class EntryStore: NSObject, BindableObject {
private lazy var fetchedResultsController: NSFetchedResultsController<Entry> = {
//[...]
fetchedResultsController.delegate = self
return fetchedResultsController
}()
var entries: [Entry] {
return fetchedResultsController.fetchedObjects ?? []
}
let didChange = PassthroughSubject<EntryStore, Never>()
//[...]
}
extension EntryStore: NSFetchedResultsControllerDelegate {
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
didChange.send(self)
}
}
Finally I pass my EntryStore
as an @EnvironmentObject
in the SceneDelegate
Though I can use other attributes of Entity
with a SwiftUI TextField, when I try and use DataField
I get this error:
Generic parameter 'Subject' could not be inferred
The code:
struct ContentView: View {
@EnvironmentObject var model: EntryStore
var body: some View {
TextField($model.entries.first!.dataFields.first!.value)
}
}
I've read that the general form of this error is a result of not explicitly typing variables, but I've tried forcibly casting this expression all sorts of ways to no avail. Also, for what it's worth, the red line in Xcode seems to be on the .allObjects
part when I moved the dataFields
conversion inline to the TextField:
TextField(($model.stringFields.allObjects.sort(by: { ($0 as! DataField).order < ($1 as! DataField).order }).first!.value)
Any ideas on how to fix this?
Upvotes: 1
Views: 1584
Reputation: 3398
The problem was that dataFields
didn't notify the PasstrhoughSubject
when it's value changed - meaning it couldn't be used as a binding.
Here's what I ended up with (also slight changes for beta 4) - first give Entry
a Publisher:
public class Entry: NSManagedObject, BindableObject {
public let willChange = PassthroughSubject<Entry, Never>()
Then use setters and getters to alert the Combine
framework of changes:
var dataFields: [DataField] {
set {
willChange.send(self)
}
get {
let arr = stringFields?.allObjects as! [DataField]
return arr.sorted(by: { $0.order < $1.order })
}
}
}
Now dataFields
can be used with bindings
Upvotes: 2