Using this question/answer I am able to use ForEach to use a NSOrderedSet created from a One to Many relationship in CoreData, however I can't seem to access a String Attribute stored in the Core Data entity.
I have two CoreData entities: Client & SessionNote. Clients can have many SessionNotes, the NSOrderedSet of clientNotes, and SessionNote can only have one Client.
Client+CoreDataClass.swift:
public class Client: NSManagedObject {
}
Client+CoreDataProperties.swift:
extension Client {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Client> {
return NSFetchRequest<Client>(entityName: "Client")
}
@NSManaged public var firstName: String?
@NSManaged public var lastName: String?
@NSManaged public var id: UUID?
@NSManaged public var clientNotes: NSOrderedSet?
}
SessionNote+CoreDataClass.swift:
public class SessionNote: NSManagedObject {
}
SessionNote+CoreDataProperties.swift:
extension SessionNote {
@nonobjc public class func fetchRequest() -> NSFetchRequest<SessionNote> {
return NSFetchRequest<SessionNote>(entityName: "SessionNote")
}
@NSManaged public var date: Date?
@NSManaged public var noteText: String?
@NSManaged public var id: UUID?
@NSManaged public var clientOrigin: Client?
}
and here is ClientDetailView.swift:
struct ClientDetailView: View {
@Environment(\.managedObjectContext) var moc
@ObservedObject var selectedClient: Client
var body: some View {
Form {
HStack {
Text("\(selectedClient.firstName ?? "") \(selectedClient.lastName ?? "")")
}
Section() {
ForEach(Array(selectedClient.clientNotes!.set), id: \.self) { note in
Text("This will repeat for the number of notes in the clientNotes NSOrderedSet")
/*
But instead I want to be able to display the noteText
string attribute stored in the SessionNote CoreData entity
instead of the above placeholder.
*/
}
}
}
}
}
I've tried Text("\(note.noteText ?? "")")
but it throws the following error:
Value of type 'AnyHashable' has no member 'noteText'
When I tried Text("\(self.selectedClient.clientNotes!.value(forKeyPath: \SessionNote.noteText))")
it throws the following error:
Protocol type 'Any' cannot conform to '_FormatSpecifiable' because only concrete types can conform to protocols
Is there anyway to display the different String values for each of the SessionNote noteText entity?
You can use array
method on NSOrderedSet
and force typecast it to [SessionNote]
, since you know that you will always be storing SessionNote
class to the ordered set.
ForEach(selectedClient.clientNotes!.array as! [SessionNote], id: \.self) { (note: SessionNote) in
Text(note.text ?? "")
}
Since this casting will be necessary in every places you wish to use the notes. You could also add a computed property inside your Client
which always gives you typed version of the SessionNote
array.
extension Client {
var typedClientNotes: [SessionNote] {
return (clientNotes?.array as? [SessionNote]) ?? []
}
}
And, with these new changes you can make your ForEach
bit better.
ForEach(selectedClient.typedClientNotes, id: \.self) { note in
Text(note.text ?? "")
}
For this reason, I try to use normal Set
for Core data relationship. Because it can be typed and makes working with Coredata so much fun. But, NSOrderedSet
has its own advantages despite of being an untyped collection.