Core Data Performance: 6 sfaturi ar trebui să știți

scrierea codului de date de bază cu performanță în minte vă ajută să vă pregătiți aplicația pentru viitor. Baza dvs. de date ar putea fi mică la început, dar poate crește cu ușurință, rezultând interogări lente și experiență scăzută pentru utilizator.

de când am început să scriu aplicația Collect by WeTransfer în 2017, am scris o mulțime de coduri legate de date de bază, atingându-l aproape în fiecare zi. Cu milioane de utilizatori adăugarea de o mulțime de conținut, efectuarea de date de bază legate de cod a devenit o abilitate importantă în echipa noastră.

Architecting SwiftUI apps cu MVC și MVVMAlthough puteți crea o aplicație pur și simplu prin aruncarea unele cod împreună, fără cele mai bune practici și o arhitectură robustă, veți termina în curând cu cod spaghete greu de gestionat. Aflați cum să creați aplicații solide și întreținute cu mai puține bug-uri folosind acest ghid gratuit.

de-a lungul anilor, am dezvoltat o mulțime de informații, pe care sunt fericit să vi le împărtășesc prin 5 sfaturi pe care ar trebui să le cunoașteți.

1: Utilizați un context de obiect gestionat în fundal

un lucru pe care nu l-am făcut de la început este utilizarea unui context de obiect gestionat în fundal. Am folosit doar contextul de vizualizare pentru a efectua orice sarcini de bază legate de date: inserarea de conținut nou, ștergerea conținutului, preluarea conținutului etc.

la început, aplicația noastră era relativ mică. Utilizarea numai a contextului de vizualizare nu a fost într-adevăr o problemă și nu a dus la sancțiuni de performanță vizibile legate de datele de bază. Evident, odată ce aplicația noastră a început să crească, ne-am dat seama că contextul de vizualizare a fost asociat cu coada principală. Interogările lente ne-au blocat interfața de utilizare și aplicația noastră a devenit mai puțin responsabilă.

în general, cea mai bună practică este de a efectua prelucrarea datelor pe o coadă de fundal, deoarece poate fi intensivă CPU. Exemple precum importul JSON în datele de bază ar putea bloca altfel contextul de vizualizare și ar duce la lipsa de reacție în interfața cu utilizatorul.

soluția este de a face uz de un context obiect gestionat de fundal. Cele mai recente API-uri facilitează crearea unui context nou din containerul dvs. persistent:

let backgroundContext = persistentContainer.newBackgroundContext()

recomand această metodă peste inițializatorul NSManagedObjectContext(concurrenyType:), deoarece va fi asociat automat cu NSPersistentStoreCoordinator și va fi setat să consume și emisiuni NSManagedObjectContextDidSave. Acest lucru menține contextul de fundal sincronizat cu contextul de vizualizare.

puteți salva acest context de fundal pe o subclasă de containere persistente particularizate. În acest fel, puteți reutiliza contextul de fundal și trebuie să gestionați doar două contexte. Acest lucru păstrează structura de date de bază simplu de înțeles și împiedică având mai multe contexte de sincronizare.

dacă trebuie să utilizați contextul de fundal doar în câteva locuri, puteți decide, de asemenea, să utilizați metoda performBackgroundTask(_:) care creează un context de fundal în loc:

persistentContainer.performBackgroundTask { (backgroundContext) in // .. Core Data Code}

cu toate acestea, această metodă creează un nou NSManagedObjectContext de fiecare dată când este invocată. Poate doriți să luați în considerare utilizarea contextului de fundal partajat dacă expediați mai des într-un context de fundal.

Important: nu treceți instanțele NSManagedObject între cozi

scrierea codului de date de bază multi-threaded este mult mai complexă decât utilizarea unui singur context de vizualizare. Motivul pentru aceasta este că nu puteți trece pur și simplu un NSManagedObject instantiat dintr-un context de vizualizare într-un context de fundal. Acest lucru ar duce la un accident și la o potențială corupție a datelor.

când este necesar să mutați un obiect gestionat dintr-o coadă în alta, puteți utiliza NSManagedObjectID care este sigur pentru fir:

let managedObject = NSManagedObject(context: persistentContainer.viewContext)backgroundContext.perform { let object = try? backgroundContext.existingObject(with: managedObject.objectID)}

2: salvarea unui context obiect gestionat numai dacă este necesar

Salvarea unui context obiect gestionat angajează toate modificările curente în magazinul părinte al contextului. După cum vă puteți imagina, aceasta nu este o operație ieftină și ar trebui utilizată numai dacă este necesar pentru a asigura performanța datelor de bază.

în primul rând, este important să verificați dacă există ceva de salvat. Dacă nu există modificări de comis, nu există nici un motiv pentru a efectua o salvare. Prin crearea unei metode saveIfNeeded vă permiteți să încorporați cu ușurință o verificare pentru aceasta:

luați în considerare cu atenție când să salvați modificările

în afară de utilizarea saveIfNeeded în loc de save(), trebuie să luați în considerare și dacă o salvare are sens. Deși un context ar putea avea modificări, nu este întotdeauna necesar să se comită direct aceste modificări.

de exemplu, dacă aveți mai multe elemente importante în baza de date, este posibil să doriți să salvați numai după ce ați importat toate elementele în contextul de fundal. O salvare este adesea urmată de actualizări UI și salvări multiple una după cealaltă ar putea duce cu ușurință la reîncărcări inutile. În plus, luați în considerare faptul că modificările salvate într-un context de fundal sunt îmbinate în contextul de vizualizare, blocând și coada principală în scurt timp. Prin urmare, fiți conștienți!

3: Descărcați doar ceea ce aveți nevoie

preluarea datelor este o sarcină costisitoare și trebuie să fiți cât mai performanți pentru a vă pregăti aplicația pentru seturi de date mari. Următorul cod este o greșeală adesea făcută:

acest cod va încărca toate obiectele inserate în memorie în timp ce este filtrat direct după ce rămâne doar cu conținut care are un nume.

este mult mai performant să folosești predicate pentru a prelua doar obiectele necesare. Filtrul de mai sus poate fi scris după cum urmează cu un NSPredicate:

acest lucru are două avantaje:

  • numai obiectele necesare sunt încărcate în memorie
  • nu trebuie să iterați peste toate obiectele

predicatele sunt foarte flexibile și ar trebui să vă permită să preluați setul de date dorit în majoritatea cazurilor, menținând în același timp performanța în datele de bază.

4: Utilizați limitele de preluare

urmând exemplul anterior, este important să setați limitele de preluare atunci când veți afișa doar o parte din setul de date.

de exemplu, spuneți că aveți nevoie doar de primele 3 nume ale tuturor elementelor de conținut. În acest caz, nu ar fi necesar să încărcați toate elementele de conținut care au un nume în memorie. Am putea preveni acest lucru prin stabilirea unei limite de preluare:

acest cod va returna doar primele 3 elemente de conținut care au un nume.

5: ștergeți mai multe obiecte simultan folosind un NSBatchDeleteRequest

în loc să iterați peste un set de date ștergând fiecare obiect unul câte unul, este adesea mai performant să utilizați un NSBatchDeleteRequest care rulează mai repede, deoarece funcționează la nivel SQL în magazinul persistent în sine.

puteți afla mai multe despre lot șterge cereri în blog-ul meu post folosind NSBatchDeleteRequest pentru a șterge loturi în datele de bază.

6: știți cum să depanați codul de date de bază

ca și în cazul tuturor codurilor pe care le scrieți, este important să știți cum să îl optimizați și să îl depanați odată ce nu funcționează conform așteptărilor. Există multe modalități de depanare care sunt cel mai bine explicate în postarea mea dedicată pe blog: depanarea datelor de bază în Xcode folosind argumente de lansare.

Architecting SwiftUI apps cu MVC și MVVMAlthough puteți crea o aplicație pur și simplu prin aruncarea unele cod împreună, fără cele mai bune practici și o arhitectură robustă, veți termina în curând cu cod spaghete greu de gestionat. Aflați cum să creați aplicații solide și întreținute cu mai puține bug-uri folosind acest ghid gratuit.

concluzie

scrierea codului de date de bază performant de la început vă ajută să vă pregătiți aplicația pentru viitoarele seturi de date mari. Deși aplicația dvs. ar putea funcționa la început, aceasta poate încetini cu ușurință odată ce baza de date și modelul dvs. cresc. Folosind un context de fundal, cereri inteligente de preluare și cereri de ștergere a lotului, faceți codul de date de bază deja mai performant.

dacă doriți să vă îmbunătățiți cunoștințele Swift, chiar mai mult, consultați pagina categoriei Swift. Simțiți-vă liber să mă contactați sau să-mi trimiteți un tweet pe Twitter dacă aveți sfaturi sau feedback suplimentar.

Multumesc!



+