Introduksjon: Hvorfor kjernedata og NSFetchedResultsController Matter

I moderne iOS-utvikling, leverer et flytende, responsivt brukergrensesnitt ofte avhenger av hvor effektivt appen din håndterer data som endres over tid. Enten du bygger et sosialt feed, en oppgave manager eller et lagersystem, er dataene som vises til brukerne sjelden statiske. Core Data - Apples modne objektgraf og utholdenhetsramme - sammen med (FRC) tilbyr en kamptestet løsning for å administrere dynamiske, store datasett samtidig som du holder UI i synkronisert uten manuelle overhead.

Denne artikkelen gir en grundig, praktisk guide til å bruke Core Data med varsler er nøkkelen. Når objekter blir satt inn, oppdatert eller slettet, sender konteksten disse endringene, som er nøyaktig hva bruker for å holde din UI konsekvent.

For offisiell utviklingsdokumentasjon, se Apples kjernedatarammereferanse.

NSFetchedResultsController: Broen mellom kjernedata og din brukergrensesnitt

er et kontrollerobjekt som er utviklet for å effektivt administrere resultatene som returneres fra en Core Data-innhentingsforespørsel, spesielt når de underliggende dataene forventes å endres. Den overvåker den relevante kontrollerte objektkonteksten og rapporterer automatisk endringer via sin delegatprotokoll.

Nøkkelfunksjoner

  • Automatisk endringssporing: FRC lytter til kontekstvarsler og oversetter dem til strukturerte delegatangrep (], ], .
  • Built-in-seksjon: Ved å angi en ], samler kontrollgruppene resultater i seksjoner, noe som gjør det trivielt å vise seksjonerte tabellvisninger eller samlingsvisninger.
  • Performanceoptimalisering: FRC bruker feiling og kasjing under hetten. Den henter bare data etter behov og kan eventuelt bruke en vedvarende cache for å unngå å bli fetching igjen når den administrerede objektkonteksten lagres.

Delegatmetoder i detalj

For å fullt ut dra nytte av kontrolleren må du implementere . Det vanligste mønsteret er å bruke disse tilbaketrekkelsene inne i en eller delegert til batch-update UI. For eksempel:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
 tableView.beginUpdates()
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
 didChange anObject: Any,
 at indexPath: IndexPath?,
 for type: NSFetchedResultsChangeType,
 newIndexPath: IndexPath?) {
 switch type {
 case .insert:
 tableView.insertRows(at: [newIndexPath!], with: .fade)
 case .delete:
 tableView.deleteRows(at: [indexPath!], with: .fade)
 case .update:
 tableView.reloadRows(at: [indexPath!], with: .fade)
 case .move:
 tableView.moveRow(at: indexPath!, to: newIndexPath!)
 @unknown default:
 tableView.reloadData()
 }
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
 tableView.endUpdates()
}

Dette mønsteret sikrer at tabellvisningen animerer endringer i synkronisering med de underliggende dataene, og forhindrer flimring eller uoverensstemmelse.

Trinn-for-steg-implementasjon

Nedenfor er et komplett, produksjonsklart eksempel ved hjelp av Swift 5, målrettet iOS 15+. Vi vil anta en enkel enhet kalt med attributter (String) og (Bool), og en (Dato).

1. Sett opp kjernedatastakken

I dine eller en dedikert (vanlig i SwiftUI-apper) opprette den vedvarende beholderen:

class PersistenceController {
 static let shared = PersistenceController()
 let container: NSPersistentContainer

 init() {
 container = NSPersistentContainer(name: "YourModelName")
 container.loadPersistentStores { storeDescription, error in
 if let error = error as NSError? {
 fatalError("Unresolved error \(error), \(error.userInfo)")
 }
 }
 container.viewContext.automaticallyMergesChangesFromParent = true
 }
}

2. Opprett NSManagedObject Subclass

Bruk Xcodes datamodellredigeringsprogramvare for å generere klassefiler, eller lag dem manuelt. Sørg for at enheten din bruker riktig klassemodulinnstilling.

3. Konfigurer henteforespørsel og FRC

I din visning kontroller, konfigurere henteforespørselen og initiere den hentede resultat kontrolleren. Det er best å utføre dette i eller en visning modell init.

lazy var fetchedResultsController: NSFetchedResultsController<Task> = {
 let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
 let sortDescriptor = NSSortDescriptor(key: "dueDate", ascending: true)
 fetchRequest.sortDescriptors = [sortDescriptor]
 // Optional: limit results with batch size for large datasets
 fetchRequest.fetchBatchSize = 20

 let controller = NSFetchedResultsController(
 fetchRequest: fetchRequest,
 managedObjectContext: PersistenceController.shared.container.viewContext,
 sectionNameKeyPath: "completionStatus", // e.g., a transient attribute or a computed property
 cacheName: nil
 )
 controller.delegate = self
 try? controller.performFetch()
 return controller
}()

4. Kjør bordvisningen med FRC

Metoder blir trivielle:

func numberOfSections(in tableView: UITableView) -> Int {
 fetchedResultsController.sections?.count ?? 0
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 let sectionInfo = fetchedResultsController.sections![section]
 return sectionInfo.numberOfObjects
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
 let task = fetchedResultsController.object(at: indexPath)
 configure(cell, with: task)
 return cell
}

Legg merke til at vi aldri ringer manuelt - delegatormetoder håndterer hver innsetting, sletting og oppdatering.

Avansert bruk og beste praksis

Trådsikkerhet

Kjernedata er ikke trådsikre. Bruk alltid [[FLT: 24]] (som kjører i hovedkøen) for alle UI-relaterte henteforespørsler og FRC. For bakgrunnsarbeid oppretter du en privat kø-kontekst og fletter endringer i visningskonteksten. Unngå å bruke den samme FRC over flere køer.

Caching

Parameteren kan forbedre oppstartsytelsen ved å fortsette delen og objektinformasjonen. Men hvis henteforespørselen eller datamodellen endres, må du slette cacheen () for å unngå korrupsjon.

Håndtering av store datasett

Bruk [[FLT: 27]] til å begrense antall objekter som hentes til minnet. Også vurdere innstilling [[FLT: 28]] bare hvis du trenger umiddelbar tilgang til alle egenskaper. For forholdsintensive data kan prefetching med [[FLT: 29]]] hindre gjentatte feil.

Integrasjon med SwiftUI

Mens er UIKit-sentrisk, kan du fortsatt bruke det i SwiftUI ved å pakke det i en eller bruke den nyere egenskapsinnpakning (som internt bruker en lignende mekanisme). For komplekse dynamiske data i SwiftUI, er vanligvis tilstrekkelig, men FRC gir deg fin-kornet kontroll over animasjoner og satsing.

Vanlige brudd og hvordan å unngå dem

  • Forgjeving : Kontrolleren vil ikke utføre hentet før du kaller denne metoden. Gjør det én gang, vanligvis rett etter initialisering.
  • Ikke sett inn delegaten: uten en delegat vil endringer ikke spre seg til tabellvisningen. Alltid ring .
  • I rette sorteringsdeskriptorer: Hvis seksjonsnavnet ikke samsvarer med den første sorteringsdeskriptoren, kan det vises deler ut av rekkefølge. Sørg for at attributten som brukes i vises i sorteringsdeskriptorer.
  • Using sammen med FRC:] Ringing mens FRC er animerende endringer kan forårsake krasj. La delegatmetodene håndtere alle UI oppdateringer.
  • Ignorerer kjernedatakontekst lagrer feil: Hvis du lagrer konteksten og en feil oppstår, kan det hende at FRC ikke blir varslet. Alltid håndtere feil og vurdere å bruke i bakgrunnskontekster.

Performance vurderinger

er allerede effektiv, men her er ytterligere optimeringer:

  • Bruke prediksjoner klokt: Et komplekst prediksjon kan bremse den første henten. Bruk indekserte attributter der det er mulig.
  • Limit hentet egenskaper: Hvis du bare trenger visse attributter, angi på henteforespørselen.
  • Batchoppdateringer: Når du gjør mange endringer, pakker du dem i en blokk for å redusere antall delegatangrep.
  • Ved unødvendig feiling: Hvis du vet at du vil få tilgang til alle objektene i et resultat sett, bruk til å forhåndsfetch dem, men vær forsiktig med minne.

For en dypere dykk i Core Data-ytelse, se Aples kjernedataytelsesguide.

Eksempler på virkelige - verden

Eksempel 1: Chatsøknad

En meldingsapp viser en liste over samtaler sortert etter siste melding. Nye innkommende meldinger bør vises umiddelbart. Ved hjelp av en FRC kan kontaktvisningen abonnere på endringer bare for den aktuelle brukerens samtaleenheter. Seksjonering etter datogrupper meldinger til ⁇ I dag ⁇ ⁇ ⁇ Jaterdag ⁇ etc.

Eksempel 2: Inventarledelse

En e-handel app viser produkter i kategorier. Når aksjenivåene endres fra en bakgrunnssynkronisering, oppdaterer FRC automatisk UI. Ved å innstilling til 50, vises visningen fortsatt responsiv selv med tusenvis av elementer.

Eksempel 3: Å gjøre liste med kategorier

Det klassiske eksempel: oppgaver gruppert i ⁇ Overdue ⁇ I dag ⁇ og ⁇ Upcoming ⁇ ] kan være en forbigående avledet attributt beregnet fra og dagens dato. Sørg for at den samme avledede verdien brukes i sortdeskriptoren for å unngå feil.

Konklusjon

Mastering kombinasjonen av Core Data og er en hjørnestein i å bygge robuste, dynamiske iOS-applikasjoner. Ved å avlaste den tunge løftingen av endringssporing og UI synkronisering til Apples rammeverk, kan du fokusere på å skape en god brukeropplevelse i stedet for å skrive kjeleplate data - styringskode.

Enten du opprettholder en arvelig UIKit-app eller vedtar SwiftUI med ], er prinsippene de samme: forstå objekt grafen din, konfigurere henteforespørsler nøye, og la den hentede resultatkontrolløren gjøre det som den gjør best. Med praksisen som er beskrevet i denne artikkelen - inkludert cacheing, trådsikkerhet og ytelsesjustering - vil du være godt - utstyrt til å håndtere alle datasett som utvikles over tid.

For ytterligere utforskning, sjekk ut Ray Wenderlichs kjernedata tutorial og ]NSHipster artikkel om NSFetchedResultsController].