Obwohl es Core Data seit vielen Jahren unter OS X und iOS gibt, wurden Batch-Updates erst kürzlich hinzugefügt. Entwickler haben seit vielen Jahren nach dieser Funktion gefragt, und Apple hat endlich einen Weg gefunden, sie in Core Data zu integrieren. In diesem Tutorial zeige ich Ihnen, wie Stapelaktualisierungen funktionieren und was sie für das Core Data Framework bedeuten.
1. Das Problem
Core Data eignet sich hervorragend für den Umgang mit Objektgrafiken. Selbst Diagramme komplexer Objekte mit vielen Entitäten und Beziehungen sind für Stammdaten kein großes Problem. Core Data weist jedoch einige Schwachstellen auf, darunter die Aktualisierung einer großen Anzahl von Datensätzen.
Das Problem ist leicht zu verstehen. Jedes Mal, wenn Sie einen Datensatz aktualisieren, lädt Core Data den Datensatz in den Speicher, aktualisiert den Datensatz und speichert die Änderungen im persistenten Speicher, z. B. einer SQLite-Datenbank.
Wenn Core Data eine große Anzahl von Datensätzen aktualisieren muss, sollte jeder Datensatz in den Speicher geladen, der Datensatz aktualisiert und die Änderungen an den persistenten Speicher gesendet werden. Wenn die Anzahl der Registrierungen zu groß ist, wird iOS aufgrund fehlender Ressourcen einfach aussteigen. Obwohl ein Gerät unter OS X möglicherweise über die Ressourcen verfügt, um die Anforderung abzuschließen, ist es langsam und verbraucht viel Speicher.
Ein anderer Ansatz besteht darin, die Datensätze stapelweise zu aktualisieren, dies erfordert jedoch auch viel Zeit und Ressourcen. Unter iOS 7 ist dies die einzige Option, die iOS-Entwicklern zur Verfügung steht. Dies ist seit iOS 8 und OS X Yosemite nicht mehr der Fall.
2. Die Lösung
Unter iOS 8 und höher sowie unter OS X Yosemite und höher ist es möglich, direkt mit dem persistenten Speicher zu sprechen und ihm mitzuteilen, was Sie ändern möchten. Dies beinhaltet normalerweise das Aktualisieren eines Attributs. Apple nennt diese Funktion Batch-Updates.
Es gibt jedoch eine Reihe von Fallstricken, auf die Sie achten müssen. Core Data erledigt viele Dinge für Sie, und Sie werden es möglicherweise erst realisieren, wenn Sie Stapelaktualisierungen verwenden. Die Validierung ist ein gutes Beispiel. Da Core Data Stapelaktualisierungen direkt für den persistenten Speicher ausführt, z. B. eine SQLite-Datenbank, kann Core Data keine Validierung für die Daten durchführen, die Sie in den persistenten Speicher schreiben. Dies bedeutet, dass Sie dafür verantwortlich sind, dass Sie dem persistenten Speicher keine ungültigen Daten hinzufügen.
Wann würden Sie Batch-Updates verwenden? Apple empfiehlt, diese Funktion nur zu verwenden, wenn der herkömmliche Ansatz zu ressourcen- oder zeitaufwändig ist. Wenn Sie Hunderte oder Tausende von E-Mails als gelesen markieren müssen, sind Stapelaktualisierungen die beste Lösung für iOS 8 und höher sowie für OS X Yosemite und höher.
3. Wie es funktioniert?
Um zu veranschaulichen, wie Stapelaktualisierungen funktionieren, empfehle ich, Done zu überprüfen, eine einfache Core Data-App, die eine Aufgabenliste verwaltet. Wir fügen der Navigationsleiste eine Schaltfläche hinzu, die jedes Element in der Liste als erledigt markiert.
Schritt 1: Projekteinrichtung
Laden Sie das Projekt herunter oder klonen Sie es von GitHub und öffnen Sie es in Xcode 7. Führen Sie die App im Simulator aus und fügen Sie einige Aufgaben hinzu.
Schritt 2: Erstellen Sie ein Balkenschaltflächenelement
Öffnen ViewController.swift und eine Eigenschaft deklarieren, checkAllButtonVom Typ UIBarButtonItem oben.
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {
let ReuseIdentifierToDoCell = "ToDoCell"
@IBOutlet weak var tableView: UITableView!
var managedObjectContext: NSManagedObjectContext!
var checkAllButton: UIBarButtonItem!
...
}
Initialisieren Sie das Balkenschaltflächenelement in der viewDidLoad() Methode von ViewController Klasse und legen Sie es als Schaltflächenelement in der linken Leiste des Navigationselements fest.
// Initialize Check All Button checkAllButton = UIBarButtonItem(title: "Check All", style: .Plain, target: self, action: "checkAll:") // Configure Navigation Item navigationItem.leftBarButtonItem = checkAllButton
Schritt 3: Implementierung checkAll(_:) Methode
das checkAll(_:) Die Methode ist ziemlich einfach, aber es gibt einige Einschränkungen, auf die Sie achten müssen. Schauen Sie sich die Implementierung unten an.
func checkAll(sender: UIBarButtonItem) {
// Create Entity Description
let entityDescription = NSEntityDescription.entityForName("Item", inManagedObjectContext: managedObjectContext)
// Initialize Batch Update Request
let batchUpdateRequest = NSBatchUpdateRequest(entity: entityDescription!)
// Configure Batch Update Request
batchUpdateRequest.resultType = .UpdatedObjectIDsResultType
batchUpdateRequest.propertiesToUpdate = ["done": NSNumber(bool: true)]
do {
// Execute Batch Request
let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
// Extract Object IDs
let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let managedObject = managedObjectContext.objectWithID(objectID)
managedObjectContext.refreshObject(managedObject, mergeChanges: false)
}
// Perform Fetch
try self.fetchedResultsController.performFetch()
} catch {
let updateError = error as NSError
print("(updateError), (updateError.userInfo)")
}
}
Erstellen Sie eine Stapelanforderung
Wir beginnen mit der Erstellung eines NSEntityDescription Beispiel für die Artikel Entität und verwenden Sie es, um a zu initialisieren NSBatchUpdateRequest Objekt. das NSBatchUpdateRequest Klasse ist eine Unterklasse von NSPersistentStoreRequest.
// Create Entity Description
let entityDescription = NSEntityDescription.entityForName("Item", inManagedObjectContext: managedObjectContext)
// Initialize Batch Update Request
let batchUpdateRequest = NSBatchUpdateRequest(entity: entityDescription!)
Wir setzen den Ergebnistyp der Stapelaktualisierungsanforderung auf .UpdatedObjectIDsResultType, ein Mitgliedswert von NSBatchUpdateRequestResultType Aufzählung. Dies bedeutet, dass das Ergebnis der Stapelaktualisierungsanforderung ein Array ist, das Objekt-IDs und Instanzen von enthält NSManagedObjectID Klasse, Datensätze, die durch die Stapelaktualisierungsanforderung geändert wurden.
// Configure Batch Update Request batchUpdateRequest.resultType = .UpdatedObjectIDsResultType
Wir bevölkern auch die propertiesToUpdate Eigenschaft der Stapelaktualisierungsanforderung. Für dieses Beispiel definieren wir propertiesToUpdate zu einem Wörterbuch, das einen Schlüssel enthält, "done"mit Wert NSNumber(bool: true). Dies bedeutet, dass jeder Artikel Datensatz wird auf gesetzt fertig, das suchen wir.
// Configure Batch Update Request batchUpdateRequest.propertiesToUpdate = ["done": NSNumber(bool: true)]
Führen Sie die Stapelaktualisierungsanforderung aus
Obwohl Stapelaktualisierungen den Kontext des verwalteten Objekts umgehen, erfolgt die Ausführung einer Stapelaktualisierungsanforderung durch Aufrufen executeRequest(_:) auf einen NSManagedObjectContext Beispiel. Diese Methode akzeptiert ein Argument, eine Instanz von NSPersistentStoreRequest Klassenzimmer. weil executeRequest(_:) ist eine Startmethode, wir führen die Methode in a do-catch Erklärung.
do {
// Execute Batch Request
let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
} catch {
let updateError = error as NSError
print("(updateError), (updateError.userInfo)")
}
Aktualisieren des Kontexts für verwaltete Objekte
Obwohl wir die Stapelaktualisierungsanforderung an einen verwalteten Objektkontext übergeben, sind dem verwalteten Objektkontext die Änderungen nicht bekannt, die sich aus der Ausführung der Stapelaktualisierungsanforderung ergeben. Wie bereits erwähnt, wird der Kontext des verwalteten Objekts umgangen. Dies gibt Batch-Updates ihre Leistung und Geschwindigkeit. Um dieses Problem zu beheben, müssen wir zwei Dinge tun:
- Verwandeln Sie verwaltete Objekte, die durch Stapelaktualisierung aktualisiert wurden, in Standardeinstellungen
- Weisen Sie den Controller über die abgerufenen Ergebnisse an, eine Extraktion durchzuführen, um die Benutzeroberfläche zu aktualisieren
Dies tun wir in den nächsten Zeilen des checkAll(_:) Methode in der do Klausel von do-catch Erklärung. Wenn die Stapelaktualisierungsanforderung erfolgreich ist, extrahieren wir das Array aus NSManagedObjectID Instanzen von NSBatchUpdateResult Objekt.
// Extract Object IDs let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
Wir gehen dann durch die objectIDs Array, fragen Sie den Kontext des verwalteten Objekts für die NSManagedObject Instanz, und verwandeln Sie es in einen Fehler durch Aufrufen refreshObject(_:mergeChanges:)Übergeben des verwalteten Objekts als erstes Argument. Um das verwaltete Objekt in einen Fehler zu zwingen, übergeben wir false als zweites Argument.
// Extract Object IDs
let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let managedObject = managedObjectContext.objectWithID(objectID)
managedObjectContext.refreshObject(managedObject, mergeChanges: false)
}
Aktualisierte Datensätze abrufen
Der letzte Schritt besteht darin, den Controller für abgerufene Ergebnisse anzuweisen, einen Abruf durchzuführen, um die Benutzeroberfläche zu aktualisieren. Wenn dies fehlschlägt, erkennen wir den Fehler in der catch Klausel von do-catch Erklärung.
do {
// Execute Batch Request
let batchUpdateResult = try managedObjectContext.executeRequest(batchUpdateRequest) as! NSBatchUpdateResult
// Extract Object IDs
let objectIDs = batchUpdateResult.result as! [NSManagedObjectID]
for objectID in objectIDs {
// Turn Managed Objects into Faults
let managedObject = managedObjectContext.objectWithID(objectID)
managedObjectContext.refreshObject(managedObject, mergeChanges: false)
}
// Perform Fetch
try self.fetchedResultsController.performFetch()
} catch {
let updateError = error as NSError
print("(updateError), (updateError.userInfo)")
}
Dies mag zwar umständlich und komplex genug für eine einfache Bedienung erscheinen, bedenken Sie jedoch, dass wir den grundlegenden Datenstapel umgehen. Mit anderen Worten, wir müssen uns um einige Haushaltsaufgaben kümmern, die normalerweise von Core Data für uns erledigt werden.
Schritt 4: Erstellen und ausführen
Erstellen Sie das Projekt und führen Sie die Anwendung im Simulator oder auf einem physischen Gerät aus. Klicken oder tippen Sie auf das Schaltflächenelement in der rechten Leiste, um jedes Aufgabenelement in der Liste zu überprüfen.

Fazit
Batch-Updates sind eine großartige Ergänzung zum Core Data Framework. Dies dient nicht nur seit vielen Jahren den Anforderungen von Entwicklern, es ist auch nicht schwierig zu implementieren, solange Sie einige Grundregeln beachten. Im nächsten Tutorial werden wir uns Batch-Löschungen genauer ansehen, eine weitere Funktion des Core Data-Frameworks, die erst kürzlich hinzugefügt wurde.
Unterstützen Sie unsere Arbeit ❤️
Wenn Ihnen dieser Artikel gefallen hat, können Sie uns mit einem Trinkgeld unterstützen, damit wir weiterhin großartige Inhalte veröffentlichen können.
























