0
votes

edit: so far i think i've narrowed the problem done to the fetchresult in listview. when the fetchrequest(predicate) changes, it doesn't refetch.


i'm building a todo app with swiftUI and Core Data. in the listView i have a button that'll change the predicate for the fetchrequest, but i can't get it to work.

code in the listView

struct HomeListView: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(fetchRequest: ItemEntity.loadItems()) var items: FetchedResults<ItemEntity>

    Text("someText")
        .onTapGesture {
            ItemEntity.predicateType.next() //next() is a method defined in core data entity class
        }

code in the core data entity class

extension ItemEntity {
    static var sortType = sort.ascending
    static var predicateType = predicate.all

    static func loadItems() -> NSFetchRequest<ItemEntity> {
        var request: NSFetchRequest<ItemEntity> = ItemEntity.fetchRequest() as! NSFetchRequest<ItemEntity>

        var predicate: NSPredicate {
        switch predicateType {
        case .all:
            return NSPredicate(format: "type = %i", 0)
        case .imur:
            return NSPredicate(format: "type = %i", 0)
        case .unimur:
            return NSPredicate(format: "type = %i", 1)
        case .imunur:
            return NSPredicate(format: "type = %i", 2)
        case .unimunur:
            return NSPredicate(format: "type = %i", 3)
        case .entry:
            return NSPredicate(format: "type = %i", 4)
        }

        request.sortDescriptors = [sortDescriptor]
        request.predicate = predicate
        return request
    }

    enum predicate {
        case all
        case imur
        case unimur
        case imunur
        case unimunur
        case entry

        mutating func next() {
            switch self {
            case .all:
                self = .imur
            case .imur:
                self = .unimur
            case .unimur:
                self = .imunur
            case .imunur:
                self = .unimunur
            case .unimunur:
                self = .entry
            case .entry:
                self = .all
            }
        }
    }
}

the idea is when user tap on the button on list view, it call the next() method and set predicateType property in ItemEntity class to another value, then the predicate property in loadItems() will update the fetchrequest, then the listview will reload.

i know there is something wrong with this approach, but i can't figure out how to fix it. Thanks for helping!

1

1 Answers

0
votes

You need to change some state so that the view re-renders.

Try adding a @State var, change it from the button action and use it in the view:

struct HomeListView: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(fetchRequest: ItemEntity.loadItems()) var items: FetchedResults<ItemEntity>
    @State private var refresh: Bool = false  // add a state
  var body: some View {
    Text("someText")
        .onTapGesture {
            ItemEntity.predicateType.next() 
            refresh.toggle()     // change the state
        }
        .background(toggle ? Color.clear : Color.clear)  // use the state
    }
}