SwiftUI中带有NSPredicate和SearchBar的ObservableObject

时间:2020-06-26 21:23:23

标签: swift swiftui combine

我正在尝试在顶部的搜索栏上创建一个People的简单列表视图。

我放下了UI,但是编辑搜索栏并没有调用didSet的{​​{1}}函数。

我相信我可能误解了@State var searchText: String@State的工作方式?好像将Binding绑定到viewModel.$searchText永远不会导致SearchBar更新。

怎么了?

@State var searchText

1 个答案:

答案 0 :(得分:0)

没关系,我想出了自己的问题。我需要@Published,而不是@State,并且$放在错误的位置。工作代码:

struct ListView: View {
    @Environment(\.managedObjectContext) var context: NSManagedObjectContext
    
    @ObservedObject var viewModel: PeopleListViewModel
    
    var body: some View {
        VStack {
            SearchBar(text: $viewModel.searchText, showsCancelButton: .constant(false))
                .padding(Edge.Set(arrayLiteral: .top, .bottom), 0)
                .padding(Edge.Set(arrayLiteral: .leading, .trailing), 8)
            List(viewModel.people, id: \.id) { (person) in
                PersonCell(person: person)
            }
        }
    }
}

extension ListView {
    final class PeopleListViewModel: NSObject, NSFetchedResultsControllerDelegate, ObservableObject {
        private let peopleController: NSFetchedResultsController<Person>
        private let sortDescriptors = [NSSortDescriptor(keyPath: \Person.name, ascending: true)]
        
        @Published var searchText: String = "" {
            didSet {
                if oldValue != searchText {
                    updatePeople()
                }
            }
        }

        init(managedObjectContext: NSManagedObjectContext) {
            peopleController = Person.resultsController(context: managedObjectContext, sortDescriptors: sortDescriptors)
            super.init()
            peopleController.delegate = self
            try? peopleController.performFetch()
        }
        
        func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
            objectWillChange.send()
        }
        
        var people: [Person] {
            return peopleController.fetchedObjects ?? []
        }
        
        func updatePeople() {
            var predicate: NSPredicate?
            
            if !searchText.isEmpty {
                predicate = NSPredicate(format: "name CONTAINS[cd] %@", argumentArray: [searchText])
            }
            
            peopleController.fetchRequest.predicate = predicate
            try? peopleController.performFetch()
        }
    }
}

extension Person {
    static func resultsController(context: NSManagedObjectContext, sortDescriptors: [NSSortDescriptor] = []) -> NSFetchedResultsController<Person> {
        let request = NSFetchRequest<Person>(entityName: "Person")
        request.sortDescriptors = sortDescriptors.isEmpty ? nil : sortDescriptors
        return NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    }
}