简体   繁体   中英

Generic parameter 'Subject' could not be inferred

Background

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

Problem

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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM