írás Core Data code teljesítmény szem előtt tartva segít felkészülni az alkalmazás a jövőben. Lehet, hogy az adatbázis kezdetben kicsi, de könnyen növekedhet, ami lassú lekérdezéseket és csökkent felhasználói élményt eredményez a felhasználó számára.
mióta 2017-ben elkezdtem írni a Collect by WeTransfer alkalmazást, sok Alapadattal kapcsolatos kódot írtam, szinte minden nap megérintve. Mivel több millió felhasználó sok tartalmat ad hozzá, az alapvető adatokkal kapcsolatos kód végrehajtása fontos készséggé vált csapatunkban.
az évek során rengeteg betekintést fejlesztettünk ki, amelyeket örömmel osztok meg veletek 5 tipp segítségével, amelyeket tudnia kell.
- 1: Használja a háttér által kezelt objektum környezetét
- fontos: Ne adja át az NSManagedObject példányokat a sorok között
- 2: csak felügyelt objektumkörnyezet mentése, ha szükséges
- gondosan mérlegelje, mikor mentse el a módosításokat
- 3:
- 4: használja a lekérési korlátokat
- 5: sok objektum törlése egyszerre az NSBatchDeleteRequest
- 6: tudja, hogyan kell hibakeresni az Alapadatkódot
- következtetés
1: Használja a háttér által kezelt objektum környezetét
egy dolog, amit nem kezdettől fogva használtunk, a háttér által kezelt objektum környezet használata. A nézet kontextust csak az alapvető adatokkal kapcsolatos feladatok elvégzésére használtuk: új tartalom beszúrása, tartalom törlése, tartalom letöltése stb.
az elején, a app viszonylag kicsi volt. Csak a nézetkörnyezet használata nem jelentett problémát, és nem eredményezett semmilyen látható teljesítménybüntetést az alapadatokkal kapcsolatban. Magától értetődően, miután alkalmazásunk növekedni kezdett, rájöttünk, hogy a nézet kontextusa a fő sorhoz kapcsolódik. A lassú lekérdezések blokkolták a felhasználói felületünket, és az alkalmazásunk kevésbé válaszolt.
általában a legjobb gyakorlat az, hogy az adatfeldolgozást háttérsorban végezzük, mivel ez CPU-intenzív lehet. Az olyan példák, mint a JSON Alapadatokba történő importálása, egyébként blokkolhatják a nézetkörnyezetet, és nem reagálhatnak a felhasználói felületen.
a megoldás az, hogy használja a háttérben kezelt objektum környezetben. A legújabb API-k megkönnyítik az új környezet létrehozását az állandó tárolóból:
let backgroundContext = persistentContainer.newBackgroundContext()
ezt a módszert a NSManagedObjectContext(concurrenyType:)
inicializátoron keresztül Ajánlom, mivel automatikusan a NSPersistentStoreCoordinator
– hoz lesz társítva, és a NSManagedObjectContextDidSave
adások fogyasztására is be lesz állítva. Ez a háttérkörnyezetet szinkronban tartja a nézetkörnyezettel.
ezt a háttérkörnyezetet egyéni állandó tároló alosztályba mentheti. Így újra felhasználhatja a háttérkörnyezetet, és csak két kontextust kell kezelnie. Ez az alapvető adatstruktúrát egyszerűen érthetővé teszi, és megakadályozza, hogy több szinkronizálatlan kontextus legyen.
ha csak néhány helyen kell használni a háttérkörnyezetet, akkor dönthet úgy is, hogy a performBackgroundTask(_:)
módszert használja, amely háttérkörnyezetet hoz létre a helyén:
persistentContainer.performBackgroundTask { (backgroundContext) in // .. Core Data Code}
ez a módszer azonban minden egyes meghíváskor új NSManagedObjectContext
értéket hoz létre. Érdemes megfontolnia a megosztott háttérkörnyezet használatát, ha gyakrabban küld háttérkörnyezet felé.
fontos: Ne adja át az NSManagedObject példányokat a sorok között
a többszálú Alapadatkód írása sokkal összetettebb, mint az egyetlen nézet kontextusának használata. Ennek az az oka, hogy nem lehet egyszerűen átadni egy NSManagedObject
példányt egy nézetkörnyezetből egy háttérkörnyezetbe. Ez összeomláshoz és potenciális adatsérüléshez vezetne.
ha egy felügyelt objektumot egyik sorból a másikba kell áthelyezni, használhatja a NSManagedObjectID
-et, amely szálbiztos:
let managedObject = NSManagedObject(context: persistentContainer.viewContext)backgroundContext.perform { let object = try? backgroundContext.existingObject(with: managedObject.objectID)}
2: csak felügyelt objektumkörnyezet mentése, ha szükséges
felügyelt objektumkörnyezet mentése az összes aktuális változtatást a kontextus szülőtárolójában végzi el. Ahogy el lehet képzelni, ez nem olcsó művelet, és csak akkor szabad használni, ha szükséges az alapadatok teljesítményének biztosítása érdekében.
először is fontos ellenőrizni, hogy van-e még valami menthető. Ha nem kell változtatásokat végrehajtani, akkor nincs ok a Mentés végrehajtására. A saveIfNeeded
módszer létrehozásával lehetővé teszi magának, hogy könnyen beépített ellenőrzést végezzen ehhez:
gondosan mérlegelje, mikor mentse el a módosításokat
a saveIfNeeded
használata mellett save()
azt is meg kell fontolnia, hogy van-e értelme a mentésnek. Bár egy kontextusban lehetnek változások, nem mindig szükséges ezeket a változásokat közvetlenül végrehajtani.
ha például fontos több elem az adatbázisba, akkor lehet, hogy csak a háttérkörnyezetben lévő összes elem importálása után szeretné menteni. A mentést gyakran követik a felhasználói felület frissítései, és több Mentés egymás után könnyen szükségtelen újratöltést eredményezhet. Emellett vegye figyelembe, hogy a háttérkörnyezetben mentett változások beolvadnak a nézetkörnyezetbe, rövidesen blokkolva a fő várólistát is. Ezért légy tudatos!
3:
az Adatok lekérése költséges feladat, és a lehető legteljesítményesebbnek kell lennie ahhoz, hogy az alkalmazás felkészüljön a nagy adatkészletekre. A következő kód gyakran elkövetett hiba:
ez a kód az összes beillesztett objektumot betölti a memóriába, miközben közvetlenül utána szűrik, hogy csak névvel rendelkező tartalommal maradjon.
sokkal hatékonyabb a predikátumok használata csak a szükséges objektumok lekérésére. A fenti szűrő lehet írni, mint majd egy NSPredicate
:
ennek két előnye van:
- csak a szükséges objektumok töltődnek be a memóriába
- nem kell minden objektumon iterálni
a predikátumok nagyon rugalmasak, és a legtöbb esetben lehetővé teszik a kívánt adatkészlet lekérését, miközben fenntartják az alapadatok teljesítményét.
4: használja a lekérési korlátokat
az előző példát követve fontos beállítani a lekérési korlátokat, amikor csak az adatkészlet egy részét fogja megjeleníteni.
például azt mondja, hogy csak az összes tartalomelem első 3 nevére van szüksége. Ebben az esetben felesleges lenne minden névvel rendelkező tartalomelemet betölteni a memóriába. Ezt megakadályozhatjuk egy lekérési korlát beállításával:
ez a kód csak az első 3 nevet tartalmazó tartalomelemet adja vissza.
5: sok objektum törlése egyszerre az NSBatchDeleteRequest
használatával ahelyett, hogy az egyes objektumokat egyenként törölné az adatkészlet felett, gyakran hatékonyabb a NSBatchDeleteRequest
használata, amely gyorsabban fut, mivel az SQL szinten működik az állandó tárolóban.
a kötegelt törlési kérelmekről többet megtudhat a blogbejegyzésemben az NSBatchDeleteRequest használatával az alapadatok kötegeinek törléséhez.
6: tudja, hogyan kell hibakeresni az Alapadatkódot
mint minden írt kódnál, fontos tudni, hogyan lehet optimalizálni és hibakeresni, ha nem a várt módon működik. A hibakeresésnek számos módja van, amelyeket a legjobban a dedikált blogbejegyzésem magyaráz meg: alapadatok hibakeresése Xcode-ban indítási argumentumok segítségével.
következtetés
a performant Core Data kód írása a kezdetektől segít előkészíteni az alkalmazást a jövőbeli nagy adatkészletekhez. Bár előfordulhat, hogy az alkalmazás az elején teljesít, könnyen lelassulhat, ha az adatbázis és a modell növekszik. A háttérkörnyezet, az intelligens lekérési kérések és a kötegelt törlési kérések használatával az Alapadatkódot már hatékonyabbá teszi.
ha még jobban szeretné fejleszteni Swift tudását, nézze meg a Swift Kategória oldalt. Ne habozzon kapcsolatba lépni velem, vagy tweet nekem a Twitteren, ha bármilyen további tippeket vagy visszajelzést.
köszönöm!