Ich versuche, Suchcode in meiner CoreData-basierten iPhone-App zu implementieren. Ich bin mir nicht sicher, wie ich vorgehen soll. Die App verfügt bereits über einen NSFetchedResultsController mit einem Prädikat zum Abrufen der Daten für die primäre TableView. Ich möchte sicherstellen, dass ich auf dem richtigen Weg bin, bevor ich zu viel Code ändere. Ich bin verwirrt, weil so viele Beispiele Array-basiert anstelle von CoreData sind.
Hier sind einige Fragen:
Benötige ich einen zweiten NSFetchedResultsController, der nur die übereinstimmenden Elemente abruft, oder kann ich dasselbe wie die primäre TableView verwenden?
Wenn ich dasselbe verwende, ist es so einfach, den FRC-Cache zu löschen und dann das Prädikat in der handleSearchForTerm: searchString-Methode zu ändern? Muss das Prädikat sowohl das ursprüngliche Prädikat als auch die Suchbegriffe enthalten, oder erinnert es sich daran, dass es überhaupt ein Prädikat zum Abrufen von Daten verwendet hat?
Wie komme ich zu den ursprünglichen Ergebnissen zurück? Setze ich das Suchprädikat einfach auf Null? Wird das nicht das ursprüngliche Prädikat töten, das zum Abrufen der FRC-Ergebnisse verwendet wurde?
Wenn jemand Beispiele für Code hat, der die Suche mit dem FRC verwendet, würde ich mich sehr darüber freuen!
Antworten:
Ich habe dies gerade in einem meiner Projekte implementiert (Ihre Frage und die andere falsche Antwort deuteten an, was zu tun ist). Ich habe Sergios Antwort ausprobiert, hatte aber Ausnahmeprobleme, als ich tatsächlich auf einem Gerät lief.
Ja, Sie erstellen zwei Controller für Abrufergebnisse: einen für die normale Anzeige und einen für die Tabellenansicht der UISearchBar.
Wenn Sie nur einen FRC (NSFetchedResultsController) verwenden, werden in der ursprünglichen UITableView (nicht in der Suchtabellenansicht, die während der Suche aktiv ist) möglicherweise Rückrufe aufgerufen, während Sie suchen, und es wird versucht, die gefilterte Version Ihres FRC falsch zu verwenden, und es werden Ausnahmen angezeigt über falsche Anzahl von Abschnitten oder Zeilen in Abschnitten geworfen.
Folgendes habe ich getan: Ich habe zwei FRCs als Eigenschaften fetchedResultsController und searchFetchedResultsController verfügbar. Der searchFetchedResultsController sollte nur verwendet werden, wenn eine Suche stattfindet (wenn die Suche abgebrochen wird, können Sie unten sehen, dass dieses Objekt freigegeben ist). Alle UITableView-Methoden müssen herausfinden, welche Tabellenansicht abgefragt wird und aus welcher FRC die Informationen abgerufen werden sollen. Die FRC-Delegatmethoden müssen auch herausfinden, welche tableView aktualisiert werden soll.
Es ist überraschend, wie viel davon Boilerplate-Code ist.
Relevante Bits der Header-Datei:
relevante Bits der Implementierungsdatei:
Ich habe eine hilfreiche Methode erstellt, um die richtige FRC abzurufen, wenn ich mit allen UITableViewDelegate / DataSource-Methoden arbeite:
Delegieren Sie Methoden für die Suchleiste:
Stellen Sie sicher, dass Sie die richtige Tabellenansicht verwenden, wenn Sie Aktualisierungen von den FRC-Delegatenmethoden erhalten:
Weitere Ansichtsinformationen:
FRC-Erstellungscode:
quelle
searchFetchedResultsController
beinil
jeder Änderung des Suchtextes auf zu setzen .cellForRowAtIndexPath
Sie in Ihrem Fall nicht die Zelle vonself.tableView
jemandem bekommen, auf den in dieser SO-Frage hingewiesen wurde ? Wenn Sie dies nicht tun, wird die benutzerdefinierte Zelle nicht angezeigt.Einige haben kommentiert, dass dies mit einem einzigen möglich ist
NSFetchedResultsController
. Das habe ich getan, und hier sind die Details. Bei dieser Lösung wird davon ausgegangen, dass Sie nur die Tabelle herausfiltern und alle anderen Aspekte (Sortierreihenfolge, Zellenlayout usw.) der Suchergebnisse beibehalten möchten.Definieren Sie zunächst zwei Eigenschaften in Ihrer
UITableViewController
Unterklasse (ggf. mit dem entsprechenden @synthesize und Dealloc):Zweitens initialisieren Sie die Suchleiste in der
viewDidLoad:
Methode IhrerUITableViewController
Unterklasse:Drittens implementieren Sie die
UISearchDisplayController
Delegatmethoden wie folgt:Schließlich wird in der
fetchedResultsController
Methode dasNSPredicate
abhängige if geändertself.searchString
:quelle
Ich habe ein paar Versuche gebraucht, um das zum Laufen zu bringen ...
Mein Schlüssel zum Verständnis war die Erkenntnis, dass hier zwei tableViews am Werk sind. Eine von meinem Viewcontroller und eine vom Searchviewcontroller verwaltete und dann konnte ich testen, welche aktiv ist und das Richtige tun. Die Dokumentation war auch hilfreich:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UISearchDisplayController_Class/Reference/Reference.html
Folgendes habe ich getan:
Das Flag searchIsActive wurde hinzugefügt:
Die Synthese in der Implementierungsdatei hinzugefügt.
Dann habe ich diese Methoden für die Suche hinzugefügt:
Dann in controllerWillChangeContent:
Und controllerDidChangeContent:
Löschen Sie den Cache, wenn Sie das Prädikat zurücksetzen.
Hoffe das hilft.
quelle
if ( [self.tableView isEqual:self.searchDisplayController.searchResultsTableView] ) { ... }
Ich stand vor der gleichen Aufgabe und fand den einfachsten Weg, sie zu lösen. Kurz gesagt: Sie müssen eine weitere Methode definieren, die
-fetchedResultsController
einem benutzerdefinierten zusammengesetzten Prädikat sehr ähnlich ist .In meinem persönlichen Fall
-fetchedResultsController
sieht mein so aus:Wie Sie sehen können, hole ich Kunden einer Agentur, die nach
agency.server_id
Prädikaten gefiltert sind . Infolgedessen rufe ich meine Inhalte auch in a abtableView
(alles, was mit der Implementierung vontableView
undfetchedResultsController
Code zusammenhängt, ist ziemlich Standard). Zur ImplementierungsearchField
definiere ich eineUISearchBarDelegate
Delegatenmethode. Ich löse es mit der Suchmethode aus, sagen wir-reloadTableView
:und natürlich Definition von
-reloadTableView
:Dieser Code-Haufen ist dem ersten "Standard" sehr ähnlich,
-fetchedResultsController
ABER in der if-else-Anweisung hier ist:+andPredicateWithSubpredicates:
- Mit dieser Methode können wir ein Prädikat festlegen, um die Ergebnisse unseres ersten Hauptabrufs im zu speicherntableView
+orPredicateWithSubpredicates
- Mit dieser Methode filtern wir den vorhandenen Abruf nach Suchabfragen aussearchBar
Am Ende setze ich ein Array von Prädikaten als zusammengesetztes Prädikat für diesen bestimmten Abruf. UND für erforderliche Prädikate ODER für optional.
Und das ist alles! Sie müssen nichts mehr implementieren. Viel Spaß beim Codieren!
quelle
Verwenden Sie eine Live-Suche?
Wenn Sie NICHT sind, möchten Sie wahrscheinlich ein Array (oder einen NSFetchedResultsController) mit den zuvor verwendeten Suchvorgängen. Wenn der Benutzer auf "Suchen" drückt, weisen Sie Ihre FetchedResults an, sein Prädikat zu ändern.
In beiden Fällen müssen Sie Ihre FetchedResults jedes Mal neu erstellen. Ich empfehle, nur einen NSFetchedResultsController zu verwenden, da Sie Ihren Code häufig duplizieren müssen und keinen Speicher für etwas verschwenden müssen, das Sie nicht anzeigen.
Stellen Sie einfach sicher, dass Sie eine NSString-Variable "searchParameters" haben und Ihre FetchedResults-Methode sie nach Bedarf für Sie neu erstellt. Verwenden Sie dazu die Suchparameter, falls verfügbar. Führen Sie einfach Folgendes aus:
Hier ist ein einfacher Code:
quelle
Swift 3.0, UISearchController, NSFetchedResultsController und Core Data
Dieser Code funktioniert unter Swift 3.0 mit
Core Data
! Sie benötigen eine einzelne Delegatmethode und einige Codezeilen zum Filtern und Suchen von Objekten aus dem Modell. Es wird nichts benötigt, wenn Sie alleFRC
und ihredelegate
Methoden sowie implementiert habensearchController
.Die
UISearchResultsUpdating
ProtokollmethodeDas ist es! Hoffe es hilft dir! Vielen Dank
quelle
SWIFT 3.0
Verwenden Sie ein Textfeld. UISearchDisplayController ist ab iOS 8 veraltet. Sie müssten einen UISearchController verwenden. Warum erstellen Sie keinen eigenen Suchmechanismus, anstatt sich mit dem Suchcontroller zu befassen? Sie können es weiter anpassen und haben mehr Kontrolle darüber und müssen sich keine Sorgen machen, dass SearchController geändert und / oder veraltet wird.
Diese Methode, die ich verwende, funktioniert sehr gut und erfordert nicht viel Code. Sie müssen jedoch Core Data verwenden und NSFetchedResultsController implementieren.
Erstellen Sie zunächst ein TextField und registrieren Sie es mit einer Methode:
Erstellen Sie dann Ihre textFieldDidChange-Methode, die im Selektor beschrieben wurde, als das Ziel hinzugefügt wurde:
Anschließend möchten Sie die Liste in der
filterList()
Methode mithilfe des NSPredicate- oder NSCompound-Prädikats filtern, wenn sie komplexer ist. In meiner filterList-Methode filtere ich basierend auf dem Namen der Entität und dem Namen des Objekts "subCategories" der Entitäten (eine Eins-zu-Viele-Beziehung).quelle
Ich denke, Luka hat dafür einen besseren Ansatz. Siehe LargeDataSetSample und seinen Grund
Er
FetchedResultsController
verwendet den Cache nicht , verwendet ihn jedoch bei der Suche. Daher werden die Suchergebnisse viel schneller angezeigt, wenn der Benutzer mehr in SearchBar eingibtIch habe seinen Ansatz in meiner App verwendet und es funktioniert OK. Denken Sie auch daran, wenn Sie mit dem Modellobjekt arbeiten möchten, machen Sie es so einfach wie möglich. Lesen Sie meine Antwort zu setPropertiesToFetch
quelle
Hier ist eine Möglichkeit, fetchedResults mit mehreren Datensätzen zu behandeln, die sowohl einfach als auch allgemein genug ist, um fast überall angewendet zu werden. Rufen Sie einfach Ihre Hauptergebnisse in einem Array auf, wenn eine Bedingung vorliegt.
Fragen Sie das Array ab, indem Sie es durchlaufen oder was auch immer Sie möchten, um eine Teilmenge Ihrer wichtigsten fetchedResults zu erstellen. Und jetzt können Sie entweder die vollständige Menge oder die Teilmenge verwenden, wenn eine Bedingung vorliegt.
quelle
Ich mochte @Josh O'Connors Ansatz, bei dem er kein a verwendet
UISearchController
. Dieser Controller (Xcode 9) weist immer noch einen Layoutfehler auf, den viele zu umgehen versuchen.Ich habe wieder a
UISearchBar
anstelle von a verwendetUITextField
, und es funktioniert ganz gut. Meine Anforderung für die Suche / Filter ist es, eine zu erstellenNSPredicate
. Dies wird an die FRC weitergegeben:...
Verbinden Sie abschließend die SearchBar mit ihrem Delegaten.
Ich hoffe das hilft anderen
quelle
Einfacher Ansatz zum Filtern vorhandener UITableView mithilfe von CoreData, der bereits nach Ihren Wünschen sortiert ist.
Dies ist buchstäblich auch mir 5 Minuten, um einzurichten und zu arbeiten.
Ich hatte eine vorhandene
UITableView
Verwendung,CoreData
die mit Daten aus iCloud gefüllt war und die ziemlich komplizierte Benutzerinteraktionen hat, und ich wollte nicht alles für eine replizieren müssenUISearchViewController
. Ich konnte einfach ein Prädikat zu dem vorhandenen hinzufügen, dasFetchRequest
bereits von der verwendet wurde,FetchResultsController
und das die bereits sortierten Daten filtert.quelle