How to deal with master/detail CoreData between SwiftUI views - core-data

I'm dealing with issue how to pass parameter selected in master view to CoreData predicate in detail view. I have this master view
struct ContentView: View {
#State private var selectedCountry: Country?
#State private var showSetting = false
#FetchRequest(entity: Country.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Country.cntryName, ascending: true)]
) var countries: FetchedResults<Country>
var body: some View {
NavigationView {
VStack {
Form {
Picker("Pick a country", selection: $selectedCountry) {
ForEach(countries, id: \.self) { country in
Text(country.cntryName ?? "Error").tag(country as Country?)
}
}
if selectedCountry != nil {
Years(cntryName: selectedCountry?.cntryName! ?? "")
}
}
}
.navigationBarTitle("UNECE Data")
.navigationBarItems(trailing: Button("Settings", action: {
self.showSetting.toggle()
}))
}
.sheet(isPresented: $showSetting) {
SettingsView(showSetting: self.$showSetting)
}
}
}
where I use Picker to select country name (from CoreData entity Country and its attribute cntryName) and pass it as String value to Years view which is coded like this
struct Years: View {
var cntryName: String
#State private var selectedDataRow: Data?
#State private var result: NSFetchRequestResult
#FetchRequest(entity: Data.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Data.dataYear, ascending: true)],
predicate: NSPredicate(format: "dataCountry == %#", "UK"), animation: .default
) var data: FetchedResults<Data>
var body: some View {
Picker("Year", selection: $selectedDataRow) {
ForEach(data, id: \.self) { dataRow in
Text(dataRow.dataYear ?? "N/A")
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: CGFloat(UIScreen.main.bounds.width), height: CGFloat(100))
.clipped()
.onAppear() {
let request = NSFetchRequest<Data>(entityName: "Data")
request.sortDescriptors = [NSSortDescriptor(key: "dataYear", ascending: true)]
request.predicate = NSPredicate(format: "dataCountry == %#", self.cntryName)
do {
self.result = try context.fetch(request) as! NSFetchRequestResult
print(self.result)
} catch let error {
print(error)
}
}
}
}
It works fine with #FetchRequest and FetchedResults stored in var data but I'm wondering how to build predicate here based on passed country name. To overcome this I considered to use onAppear section and classic NSFetchRequest and NSFetchRequestResult which causes compiler error "'Years.Type' is not convertible to '(String, NSFetchRequestResult, FetchRequest) -> Years'" in the line
Years(cntryName: selectedCountry?.cntryName! ?? "")
of ContentView struct. Error disappear if I comment the line
#State private var result: NSFetchRequestResult
in Years struct but it obviously causes another error. So I'm lost in circle. What`s recommended practice here, please?
Thanks.

Finally I found the way thanks to this post SwiftUI use relationship predicate with struct parameter in FetchRequest
struct Years: View {
var request: FetchRequest<Data>
var result: FetchedResults<Data> {
request.wrappedValue
}
#State private var selectedDataRow: Data?
init(cntryName: String) {
self.request = FetchRequest(entity: Data.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Data.dataYear, ascending: true)],
predicate: NSPredicate(format: "dataCountry == %#", cntryName), animation: .default)
}
var body: some View {
VStack {
Picker("Year", selection: $selectedDataRow) {
ForEach(result, id: \.self) { dataRow in
Text(dataRow.dataYear ?? "N/A").tag(dataRow as Data?)
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: CGFloat(UIScreen.main.bounds.width), height: CGFloat(100))
.clipped()
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Total polutation: ")
.alignmentGuide(.leading) { dimension in
10
}
if selectedDataRow != nil {
Text(String(describing: selectedDataRow!.dataTotalPopulation))
} else {
Text("N/A")
}
}
}}
}
}

Related

Swiftui-Picker doesn't show selected value [duplicate]

This question already has an answer here:
Choosing CoreData Entities from form picker
(1 answer)
Closed 9 months ago.
Initial position: making two pickers filled from database where the second depends on the first. I followed this Picker Values from a previous picker - CoreData/SwiftUI example and it works pretty good.
Only one problem: the second picker doesn't show the selected value.
#State var courtSelected = 0
#State var judgeSelected = 0
HStack{
Picker(selection: $courtSelected, label: Text("Gericht \(courtSelected)")){
ForEach(0..<courts.count){ court in
Text("\(courts[court].name ?? "Unknown")")
}
}
}
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
ForEach(Array(courts[courtSelected].courtsJudges! as! Set<Judges>), id: \.self) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")")
}
}
}
Only differences:
the modification from NSSet to array
I had to change #Binding var judgeSelected:Int to #State, because otherwise I have to hand over the judge selected as Parameter beginning from App-Struct.
Printing the $judgeSelected inside the label demonstrates, that this var is never changed.
Your selection and presentation are differ by type, so add tag:
Picker(selection: $courtSelected, label: Text("Gericht \(courtSelected)")){
ForEach(0..<courts.count){ court in
Text("\(courts[court].name ?? "Unknown")").tag(court) // << here !!
}
}
Second picker presents objects, so selection should also be an object, like
#State var judgeSelected: Judges? = nil
Next shows similar case so should be helpful https://stackoverflow.com/a/68815871/12299030
try something like this:
HStack{
Picker(selection: $courtSelected, label: Text("Gericht \(courtSelected)")){
ForEach(0..<courts.count){ court in
Text("\(courts[court].name ?? "Unknown")")
}
}
}
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
// -- here
ForEach(Array(Set(courts[courtSelected].courtsJudges!)), id: \.self) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")")
}
}.id(UUID()) // <-- here
}
}
Note also the second ForEach with Set. PS, do not use forced unwrap, ie. no ! in your code.
EDIT-1: to avoid the error with arrayLiteral, try this:
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
if let theJudges = courts[courtSelected].courtsJudges {
ForEach(Array(Set(theJudges)), id: \.self) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")")
}
}
}.id(UUID())
}
EDIT-2:
here is my test code that allows the second picker
to depend on the first picker. I used both the id marker, and tag that
must match the selection type.
Since you don't show your struct code for court and judge,
I created some example structs for those.
You will have to adjust the code to cater for your structs.
Used the id of the Judge struct in the second picker for the tag.
However, there are other ways to have a Int tag, for example using array indices, such as:
struct Judge: Identifiable, Hashable {
var id: Int
var gender: String?
var name: String?
var title: String?
}
struct Court: Identifiable, Hashable {
var id: Int
var name: String?
var courtsJudges: [Judge]?
}
struct ContentView: View {
#State var courtSelected = 0
#State var judgeSelected = 0
#State var courts: [Court] = [
Court(id: 0, name: "one",
courtsJudges: [
Judge(id: 0, gender: "Male", name: "name1", title: "title1"),
Judge(id: 1, gender: "Male", name: "name2", title: "title2"),
Judge(id: 2, gender: "Male", name: "name3", title: "title3")
]),
Court(id: 1, name: "two",
courtsJudges: [
Judge(id: 3, gender: "Female", name: "name7", title: "title7"),
Judge(id: 4, gender: "Female", name: "name8", title: "title8"),
Judge(id: 5, gender: "Female", name: "name9", title: "title9")
])
]
var body: some View {
VStack (spacing: 77) {
HStack{
Picker(selection: $courtSelected, label: Text("Gericht \(courtSelected)")){
ForEach(0..<courts.count) { court in
Text("\(courts[court].name ?? "Unknown")").tag(court)
}
}
}
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
if let theJudges = courts[courtSelected].courtsJudges {
ForEach(Array(Set(theJudges))) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")")
.tag(judge.id)
}
}
}.id(UUID())
}
}.padding()
}
}
Alternatively:
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
if let theJudges = courts[courtSelected].courtsJudges, let arr = Array(Set(theJudges)) {
ForEach(arr.indices, id: \.self) { index in
Text("\(arr[index].gender ?? "") \(arr[index].title ?? "") \(arr[index].name ?? "")")
.tag(index)
}
}
}.id(UUID())
}
First: thanks for all the great help so far.
Bringing it all together til now.
The following code creates a picker, but the selection is not shown. Changing to a radioGroup, you can't select anything.
Here's my edited code
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Courts.name, ascending: true)],
animation: .default
)
private var courts: FetchedResults<Courts>
#State var courtSelected = 0
#State var judgeSelected = 0
var body: some View {
HStack{
Picker(selection: $courtSelected, label: Text("Gericht")){
ForEach(0..<courts.count){ court in
Text("\(courts[court].name ?? "Unknown")").tag(court)
}
}
}
HStack {
Picker(selection: $judgeSelected, label: Text("Richter \(judgeSelected)")){
ForEach(Array(courts[courtSelected].courtsJudges as! Set<Judges>), id: \.self) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")").tag(judge)
}
}.id(UUID())
}
}
}
The next code still leads to an error
HStack {
Picker(selection: $judgeSelected, label: Text("Richter: (\(judgeSelected))")){
if let theJudges = courts[courtSelected].courtsJudges {
ForEach(Array(Set(theJudges)), id: \.self) { judge in
Text("\(judge.gender ?? "") \(judge.title ?? "") \(judge.name ?? "")")
}
}
}.id(UUID())
}
I think, the problem has to be anywhere else, because already at the start the picker doesn't show anything and the radios are grey.
Is it, because picker 2 depends on picker 1 and changes when a value in picker 1 is selected?
It's all for macOS on xcode 13.4.1
I created a complete new project with core data, added two entities (Courts and Judges) with two attributes each (id and name).
Then I only made this view:
import SwiftUI
import CoreData
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Courts.name, ascending: true)],
animation: .default
)
private var courts: FetchedResults<Courts>
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Judges.name, ascending: true)],
animation: .default
)
private var judges: FetchedResults<Judges>
#State var courtSelected = 0
#State var judgeSelected = 0
var body: some View {
if(courts.count > 0) {
HStack{
Picker(selection: $courtSelected, label: Text("Gericht")){
ForEach(0..<courts.count){ court in
Text("\(courts[court].name ?? "Unknown")").tag(court)
}
}
}
HStack {
Picker(selection: $judgeSelected, label: Text("Richter \(judgeSelected)")){
ForEach(Array(courts[courtSelected].courtsJudges as! Set<Judges>), id: \.self) { judge in
Text("\(judge.name ?? "")").tag(judge)
}
}.id(UUID())
}
HStack {
Button("neue Gerichte") {
addItem()
addJudges()
}
}
}
}
private func addItem() {
for id in 0..<3 {
let newItem = Courts(context: viewContext)
newItem.id = UUID()
newItem.name = "Gericht Nr. \(id)"
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
private func addJudges() {
for cd in 0..<courts.count {
for jd in 0..<3 {
let newJudge = Judges(context: viewContext)
newJudge.id = UUID()
newJudge.name = "Richter \(jd) am Gericht \(courts[cd].name)"
newJudge.judgesCourts = courts[cd]
try? viewContext.save()
}
}
}
}
The result: both pickers are shown, first ist ok, second shows the right judges, but they are not "selectable"

SwiftUI: When I unlock apps it takes me back to the list

I have some problem with my application. When I lock it while I am in the content view and then unlock it, it takes me back to the list. I would like the view I was in before locking to still be visible after unlocking. I have tried to get this effect somehow but not successfully. Please, give me a hint.
What is more, if I click the heart and the item is marked as favorite, it also moves me back to the list. Here I would also like to remain in the view after selecting the heart. How can I eliminate this?
Here is a sample usage using Apple's sample code since you didn't provide any entity info
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
//SceneStorage to preserve the selected item by the user
#SceneStorage("ContentView.selection") var selection: String?
var body: some View {
NavigationView {
List {
ForEach(items) { item in
//Use the NavigationLink that uses selection
NavigationLink(tag: item.objectID.description, selection: $selection,
destination: {
//to edit/ observe the item pass it to an #ObservedObject
EditItemView2(item: item)
}, label: {
VStack{
Text(item.timestamp!, formatter: itemFormatter)
}
})
Button("delete", action: {
withAnimation(.easeOut(duration: 2)){
try? viewContext.delete(item)
}
})
}.onDelete(perform: deleteItems)
}
}
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
#endif
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Select an item")
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation(.easeOut(duration: 2)) {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
struct EditItemView2: View{
//This observes the item and allows changes to the object
#ObservedObject var item: Item
var body: some View{
DatePicker("timestamp", selection: $item.timestamp.bound)
}
}
This page talks all about it
https://developer.apple.com/documentation/uikit/view_controllers/restoring_your_app_s_state_with_swiftui
If your view is the first to create your UserSettings object, I recommend that you use #StateObject instead of #ObservedObject—and especially if that object is the only owner of the view and is not being observed by any other view.

Unable to use ForEach for distinct records from coredata

I have a table that contains 20 songs from 5 different artists, this number can go up and down , now i want a View where i can display a navigation of these unique singers with their images that are also in table.
So i need only distinct records based on artistname, i query coredata but when i use it in View , i get Generic struct 'ForEach' requires that 'NSFetchRequest<NSDictionary>' conform to 'RandomAccessCollection'
Now to overcome this i use id:.self, this also does not work.
Now i read and learn that ForEach does not like any TYPE that is not sorted , but i have not been able to find a way around this, can any one kindly suggest any solutions, thanks.
This is how i fetch the unique records from core data
let fetchRequest: NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: "Artists")
init(songLVM: Binding<SongListVM>){
_songLVM = songLVM
fetchRequest.propertiesToFetch = ["artistname"]
fetchRequest.returnsDistinctResults = true
fetchRequest.resultType = .dictionaryResultType
}
Below is the entire file
import Foundation
import SwiftUI
import CoreData
struct ArtistList: View {
#Environment(\.managedObjectContext) var managedObjectContext
#Binding var songLVM: SongListVM
#State var namesFilter = [String]()
//-----
let fetchRequest: NSFetchRequest<NSDictionary> = NSFetchRequest(entityName: "Artists")
init(songLVM: Binding<SongListVM>){
_songLVM = songLVM
fetchRequest.propertiesToFetch = ["artistname"]
fetchRequest.returnsDistinctResults = true
fetchRequest.resultType = .dictionaryResultType
}
//-----
var body: some View {
List {
ForEach(fetchRequest) { <---- Error here
idx in
NavigationLink(
destination: ArtistSongs(artistName: idx.artistname ?? "no name", songLVM: $songLVM)) {
ZStack(alignment: .bottomTrailing) {
Image(uiImage: UIImage(data: idx.artistImage ?? Data()) ?? UIImage())
.resizable()
.frame(width: 350, height: 350, alignment: .center)
Text(idx.artistname ?? "no name")
.font(Font.system(size: 50, design: .rounded))
.foregroundColor(.white)
}
}
}
}
}
}
once you figure out what your dictionary is, try this in your ForEach loop:
ForEach(dict.sorted(by: >), id: \.key) { key, value in
...
}
EDIT1:
#FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Artists.artistname, ascending: true)],
animation: .default)
private var artists: FetchedResults<Artists>
...
ForEach(artists, id: \.self) { artist in
...
}

SwiftUI CoreData - How to update the fetch request and the list

I am creating an application in SwiftUI using CoreData and I have a problem. In application you can add song to favorites and it will be added to list (FavoriteSongsView). Until the song is added to favorites everything is fine. In DetailView I click the button and the "heart.fill" icon and the song is added to the list. However, if I click on the icon again to un-favorite the song, it does not disappear from the list. I fought with it a little bit but without any effect. Could you please point out the cause of the problem?
List of favorite songs:
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(
entity: Song.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Song.number, ascending: true)],
predicate: NSPredicate(format: "favorite <> 'false'")
) var songs: FetchedResults<Song>
var body: some View {
NavigationView{
VStack{
List {
ForEach(songs, id:\.self){ song in
NavigationLink(destination: DetailView(song: song, isSelected: song.favorite)) {
HStack{
Text("\(song.number). ") .font(.headline) + Text(song.title ?? "No title")
}
}
}
}
}
.listStyle(InsetListStyle())
.navigationTitle("Favorite")
}
}
}
Detailed view:
struct DetailView: View {
#State var song : Song
#State var isSelected: Bool
#State var wrongNumber: Bool = false
var body: some View {
VStack{
Text(song.content!)
.padding()
Spacer()
}
.navigationBarTitle("\(song.number). \(song.title ?? "No title")", displayMode: .inline)
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
HStack{
Button(action: {
song.favorite.toggle()
PersistenceController.shared.save()
isSelected=song.favorite
}) {
Image(systemName: "heart.fill")
.foregroundColor(isSelected ? .red : .blue)
}
Button(action: {
alert()
}) {
Image(systemName: "1.magnifyingglass")
}
NavigationLink("DetailView", destination: DetailView(song: song, isSelected: isSelected))
.frame(width: 0, height: 0)
.hidden()
}
}
}
}
}
Use this NSPredicate
NSPredicate(format: "favorite = %d", false)

Is there a way to modify fetched results with a predicate after they are initialized?

I am trying to build a search view for an existing CoreData app (simple logging app).
I have all the data stored with CoreData and is fetched with the #FetchRequest:
#State private var searchPredicate: NSPredicate? = NSPredicate(format: "title contains[c] %#", "")
#FetchRequest( entity: Item.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Item.title, ascending: true)],
predicate: NSPredicate(format: "title contains[c] %#", "h")
)
var items: FetchedResults<Item>
It now only fetches the items that pass the predicate test which in this case are all the ones that contain an "h".
I then display the results in a List in the body of the SearchView:
List {
ForEach(Items) { Item in
ListViewItem(title: Item.title!, subTitle: Item.subTitle!, createdAt: "\(Item.createdAt!)")
}
}
I then created a new class "Searchbar" which is called in the searchview and is supposed to create a predicate based on the input of the search field and then pass it on as a Binding to the parent where then based on that predicate the correct items can be displayed.
Calling the searchbar at the top of a VStack in the searchview:
SearchBar(text: $searchText, predicate: $searchPredicate)
The Bindings change depending on the user input in the "searchBar":
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
predicate = NSPredicate(format: "title contains[c] %#", searchText)
}
So far so good...
The problem I have now run into is that we have a predicate that works but can't be called within the #Fetchrequest in the definitions since it would be called before its initialized.
#State private var searchPredicate: NSPredicate? = NSPredicate(format: "title contains[c] %#", "")
#FetchRequest(
entity: Item.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \Item.title, ascending: true)
],
predicate: searchPredicate
) var items: FetchedResults<Item>
This gives me the error that the property initializer can't be run before self is available which is logical but makes me wonder and brings me back to my question: Is there a way to modify fetched results with a predicate after they are initialized?
I have also tried calling predicate related methods on the fetched results in the ForEach() statement but none of them seemed to have worked.
If there are any questions please do not hesitate to ask.
Is there a way to modify fetched results with a predicate after they
are initialized?
Well... no, not in the way you try to do this, and even if you'd try to create it with NSFetchRequest instance, which is reference, and allows to change predicate later, that wouldn't work, because SwiftUI's FetchRequest stores copy of provided fetch request (or creates own with provided parameters)... so, no. But...
You can break apart view providing fetch request parameters with view constructing fetch request and showing result.
Here is a demo of approach (important part of it) which gives you possibility to get results with different dynamically changed predicates:
struct MasterView: View {
#State var predicate: NSPredicate? = nil
var body: some View {
VStack {
Button(action: { // button just for demo
self.predicate = NSPredicate(format: "title contains[c] %#", "h")
}, label: { Text("Filter") })
ResultView(predicate: self.predicate)
}
}
}
struct ResultView: View {
#FetchRequest
var events: FetchedResults<Event>
#Environment(\.managedObjectContext)
var viewContext
init(predicate: NSPredicate?) {
let request: NSFetchRequest<Event> = Event.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Event.timestamp, ascending: true)]
if let predicate = predicate {
request.predicate = predicate
}
_events = FetchRequest<Event>(fetchRequest: request)
}
var body: some View {
List {
ForEach(events, id: \.self) { event in
...
I decided to post the fully working version possible with the great answer provided by Asperi since I haven't found a working solution anywhere else.
struct MasterView: View {
#State var predicate: NSPredicate? = nil
#State private var searchText = ""
var body: some View {
VStack {
TextField("Search", text: $searchText, onEditingChanged: {_ in
self.predicate = NSPredicate(format: "title contains[c] %#", "\(self.searchText)")
print("THE PREDICATE: \(String(describing: self.predicate))")
}, onCommit: {
print("onCommit")
}).foregroundColor(.primary)
SearchView(predicate: self.predicate)
}
}
}
And the SearchView:
struct SearchView: View {
#State private var searchText = ""
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest var items: FetchedResults<Item>
init(predicate: NSPredicate?) {
let request: NSFetchRequest<Item> = Item.fetchRequest() as! NSFetchRequest<Item>
request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.title, ascending: true)]
if let predicate = predicate {
request.predicate = predicate
}
_items = FetchRequest<Item>(fetchRequest: request)
}
var body: some View {
VStack {
List {
...
As a little update to what #Asperi answered (Swift 5.4 Xcode 12.5), in the ResultView you can do this now:
var fetchRequest: FetchRequest<Event>
init(predicate: NSPredicate?) {
fetchRequest = FetchRequest<Event>(entity:
Event.entity(), sortDescriptors: [NSSortDescriptor(keyPath:
\Event.timestamp, ascending: true)], predicate: predicate)
}
As FetchRequest takes NSPredicate? in its constructor:
public init(entity: NSEntityDescription, sortDescriptors: [NSSortDescriptor], predicate: NSPredicate? = nil, animation: Animation? = nil)

Resources