Advertisement
  1. Code
  2. Core Data

Was ist ein Kern-Daten-Fehler?

Scroll to top
Read Time: 12 min

German (Deutsch) translation by Max Benjamin (you can also view the original English article)

Fehler sind ein wesentlicher Bestandteil von Core Data. Obwohl der Begriff klingt bedrohlich, Fehler die auf dem Lebenszyklus eines Core-Data-record. In diesem tutorial werden Sie lernen, was Fehler sind, wie mit Ihnen umzugehen ist, und wie man Debuggen von Problemen im Zusammenhang zu bemängeln.

Voraussetzungen

Core Data ist ein Thema für fortgeschrittene, so gehe ich davon aus, dass Sie bereits vertraut mit Xcode und iOS Entwicklung. Obwohl ich werde mit der Swift Programmiersprache, die für dieses tutorial, alles, was in diesem tutorial gilt auch für Objective-C.

Wat Ist das ein Fehler?

Core Data ist sehr gut in dem was er tut, Dank der harten Arbeit von apples Core-Data-team. Core Data ist äußerst optimiert zu halten, der Speicherbedarf geringer, ohne Leistung zu opfern. Fehlgeschlagenes ist eine der Techniken, die Core-Daten verwendet, um zu konsumieren, so wenig Speicher wie möglich.

Fehlgeschlagenes nicht eindeutig zu zentralen Daten. Eine ähnliche Technik wird verwendet, in vielen anderen frameworks wie Ember und Ruby on Rails. Die Idee ist einfach, nur die Daten laden, wenn Sie benötigt wird. Um fehlerhafte arbeiten, die Kern-Daten muss ein wenig Magie unter die Haube durch das erstellen von benutzerdefinierten Unterklassen zur compile-Zeit, die für die Fehler. Mal sehen, wie das funktioniert mit einem Beispiel.

Ich habe eine einfache Beispielanwendung, mit zu arbeiten. Laden Sie die Xcode-Projekt von GitHub und öffnen Sie Sie in Xcode. Das Projekt nutzt Swift 2.1, was bedeutet, dass Sie benötigen Xcode 7.1 oder höher, um die Befriedigung der compiler.

Das Datenmodell enthält zwei Elemente, Liste und Element. Eine Liste kann null oder mehr Elemente, und ein Element ist immer verbunden mit einer Liste. Es ist ein klassisches Beispiel für eine eins-zu-viele-Beziehung.

Data ModelData ModelData Model

Führen Sie die Anwendung, und füllen Sie die persistente Speicherung, eine SQLite-Datenbank mit einigen Daten, indem ein paar Listen und Elemente. Beenden Sie die Anwendung, wenn Sie fertig sind.

Brennen Fehler

Sie sollten jetzt eine Anwendung mit einigen Daten. Mal sehen, wie Fehler in der Praxis funktionieren, indem Sie einige print-Anweisungen. Öffnen ListsViewController.swift und suchen prepareForSegue(_:sender: -). In dieser Methode, die wir abrufen der Liste der Benutzer ausgewählt hat, in der Tabelle anzeigen. Kommentieren Sie die print-Anweisungen in prepareForSegue(_:sender: -), wie gezeigt, in der Umsetzung weiter unten.

1
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
2
    if segue.identifier == SegueListViewController {
3
        guard let indexPath = tableView.indexPathForSelectedRow else { return }
4
        
5
        // Fetch List

6
        let list = self.fetchedResultsController.objectAtIndexPath(indexPath) as! List
7
        
8
        print("1: \(list)")
9
        
10
        if let items = list.items {
11
            print("2: \(items)")
12
            print("3: \(items.count)")
13
            print("4: \(items)")
14
            
15
            if let item = items.anyObject() {
16
                print("5: \(item)")
17
                print("6: \(item.name)")
18
                print("7: \(item)")
19
            }
20
        }
21
        
22
        print("8: \(list)")
23
        
24
        // Fetch Destination View Controller

25
        let listViewController = segue.destinationViewController as! ListViewController
26
        
27
        // Configure View Controller

28
        listViewController.list = list
29
    }
30
}

Führen Sie die Anwendung und Tippen Sie auf eine der Listen in der Listen-Ansicht-controller. Das Beispiel ist nur interessant, wenn Sie Tippen Sie auf eine Liste mit einem oder mehreren Elementen zugeordnet. Lassen Sie uns untersuchen Sie die Ausgabe der print-Anweisungen Schritt für Schritt.

1
1: <Faulting.List: 0x154e5d0b0> (entity: List; id: 0xd0000000001c0000 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/List/p7> ; data: {
2
    items = "<relationship fault: 0x154e3d5b0 'items'>";
3
    name = "List 6";
4
})

Das erste, was zu beachten ist der name der Klasse, Fehlgeschlagenes.Liste. Dies ist, was wir erwarten, da das Modul benannt wird, der zu einem Fehler und die Klasse mit dem Namen Liste. In Swift, die komplette Klasse name einer Klasse besteht aus dem Modulnamen und den Namen der Klasse ein.

Die Ausgabe in der Konsole zeigt auch den Namen der Entität, Liste oder ein Wörterbuch der Daten. Das name-Attribut gesetzt ist, Liste 6, während das Attribut items markiert ist, als eine Beziehung Schuld. Dies ist die erste Art von Fehler in Core Data. Core Data versteht, dass es keine Notwendigkeit gibt, laden Sie die Beziehung. Stattdessen markiert er die Beziehung als Fehler. Die zweite print-Anweisung bestätigt dies, wie Sie unten sehen können.

1
2: Relationship 'items' fault on managed object (0x154e5d0b0) <Faulting.List: 0x154e5d0b0> (entity: List; id: 0xd0000000001c0000 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/List/p7> ; data: {
2
    items = "<relationship fault: 0x154e3d5b0 'items'>";
3
    name = "List 6";
4
})

In der Dritten print-Anweisung, ist jedoch mehr interessant. Es gibt die Anzahl der Elemente, die der Liste zugeordnet.

1
3: 2

Core Data kann dies nur tun, indem er die Beziehung Schuld. Es fordert den permanenten Speicher für die Elemente, die der Liste zugeordnet. Dies ist jedoch nur ein Teil der Geschichte wie dargestellt durch die vierte print-Anweisung.

1
4: Relationship 'items' on managed object (0x154e5d0b0) <Faulting.List: 0x154e5d0b0> (entity: List; id: 0xd0000000001c0000 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/List/p7> ; data: {
2
    items =     (
3
        "0xd000000000540002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p21>",
4
        "0xd000000000580002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p22>"
5
    );
6
    name = "List 6";
7
}) with objects {(
8
    <Faulting.Item: 0x154e83d60> (entity: Item; id: 0xd000000000540002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p21> ; data: <fault>),
9
    <Faulting.Item: 0x154e55e50> (entity: Item; id: 0xd000000000580002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p22> ; data: <fault>)
10
)}

Wir sehen nicht mehr, eine Beziehung Schuld ist, aber wir immer noch einen Fehler sehen. Was ist das? Core Data kann nur geben uns die Anzahl der Elemente für die Liste der Entlassung oder die Auflösung der Beziehung Schuld. Jedoch, dies bedeutet nicht, dass Core Data behebt die Elemente der Beziehung. Die Ausgabe in der Konsole bestätigt dies.

Wir können sehen, dass die Einträge für die Elemente gibt es, einschließlich der id Core Data verwendet intern. Das data dictionary, jedoch ist markiert als Fehler. Wieder, Core Data gibt uns nur, was wir bitten. Zum Glück, die nitty gritty details behandelt werden, die von Core Data.

Lassen Sie uns ein wenig tiefer Graben, und hol eines der Elemente aus der Liste. Wir tun dies durch aufrufen anyObject() auf die Elemente Objekt. Wir drucken das resultierende Element in die fünfte print-Anweisung.

1
5: <Faulting.Item: 0x144d7f100> (entity: Item; id: 0xd000000000540002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p21> ; data: <fault>)

Die Ausgabe dürfte Sie nicht überraschen. Die Ausgabe bestätigt, dass wir ' re Umgang mit einem Element Einheit. Wenig überraschend ist, dass das data-dictionary ist immer noch gekennzeichnet als ein Fehler. In der sechsten Kontoauszug drucken, wir drucken das name-Attribut des Elements.

1
6: Item 0

Da bitten wir um den Wert eines Attributs des Datensatzes, Core Data feuert die Schuld zu geben, uns das Wert. Es holt sich die Daten für das Element und fügt das Daten-dictionary. Die siebte print-Anweisung bestätigt diese Ergebnisse.

1
7: <Faulting.Item: 0x144d7f100> (entity: Item; id: 0xd000000000540002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p21> ; data: {
2
    list = "0xd0000000001c0000 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/List/p7>";
3
    name = "Item 0";
4
})

Das data dictionary enthält das name-Attribut als auch die Liste Beziehung. Die achte und Letzte print-Anweisung zeigt, dass die Beziehung Schuld des list-Objekts aufgelöst wird.

1
8: <Faulting.List: 0x144e55da0> (entity: List; id: 0xd0000000001c0000 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/List/p7> ; data: {
2
    items =     (
3
        "0xd000000000540002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p21>",
4
        "0xd000000000580002 <x-coredata://804E0602-42B4-4EB5-A1D0-653848363595/Item/p22>"
5
    );
6
    name = "List 6";
7
})

Nicht zur Erfüllung einer Schuld

Ich beschloss, diesen Artikel zu schreiben, zu erklären, ein problem, das viele Entwickler mit Core Data laufen in der einen oder anderen Stelle brennen ein Fehler, der nicht erfüllt werden kann. Das problem ist einfach. Angenommen, Sie haben eine Liste mit der Anzahl der Elemente und, irgendwann, wird der Benutzer löscht die Liste. Was passiert mit den items auf der Liste? Was passiert, wenn Core Data versucht, Feuer auf der Liste Beziehung eines der Elemente, die im Besitz dieser Liste? Wir finden es heraus.

Lasst uns das Projekt, das Sie heruntergeladen haben, von GitHub. Öffnen Sie Faltenbildung.xcdatamodeld, die Projekt-Daten-Modell. Wählen Sie die Elemente, die Beziehung der Liste Entität und öffnen Sie die Data Model-Inspector auf der rechten Seite. Was für uns von Interesse ist die Regel Löschen, die derzeit festgelegt ist, zu überlappen. Dies bedeutet, dass jedes Element der Liste wird gelöscht, wenn die Liste gelöscht wird. Dies macht Sinn, da wir nicht möchten, verlassen zu haben Gegenstände, die nicht im Zusammenhang mit einer Liste.

Delete Rule CascadeDelete Rule CascadeDelete Rule Cascade

Wählen Sie in der Liste Beziehung des Elements Person und öffnen Sie die Data Model-Inspector. Die Regel Löschen dieser Beziehung eingestellt ist, Zunichte gemacht. Dies bedeutet, dass das Ziel der Beziehung, in der Liste Objekt auf den Wert null gesetzt, wenn das Ziel-Datensatz ist, wird das Element gelöscht. Dies ist die Standard-Regel löschen für eine Beziehung.

Delete Rule NullifyDelete Rule NullifyDelete Rule Nullify

Führen Sie die Anwendung, erstellen Sie ein paar Listen und Elemente, und Tippen Sie auf die Elemente auf die Schaltfläche oben Links, um zu zeigen, jedes Element, die Sie erstellt haben. Tippen Sie auf Abbrechen in der oberen linken, löschen Sie eine der Listen, und Tippen Sie auf die Elemente, die Taste erneut, um zu sehen, was sich verändert. Wie erwartet, werden die Elemente im Zusammenhang mit der Liste gelöscht wurden auch gelöscht von Core Data. Dies ist keine Magie. Core Data führt einfach die delete-Regeln, die wir im Datenmodell definierten.

Wir können feststellen, dass die Beziehungen korrekt eingerichtet sind, für diese Art von Anwendung. Aber was passiert, wenn wir nicht so konfigurieren das löschen von Regeln korrekt. Öffnen Sie die data model und legen Sie die Regel löschen der beiden Beziehungen, Gegenstände und Liste, Keine Aktion. Starten Sie die Anwendung erneut, und erstellen Sie ein paar Listen und Elemente. Wenn Sie nach dem löschen einer Liste aus und Tippen Sie auf die Elemente, die die Schaltfläche in der oberen linken, um zu sehen, jedes Element in die persistente Speicherung, die zugehörigen Elemente gelöscht, die Liste sollte noch da sein. Sie wurden nicht gelöscht, obwohl die Liste, zu denen Sie gehören entfernt wurde.

Tippen Sie auf eine der Listen und sehen, was passiert. Wenn Sie die Anwendung auf iOS 8, wird die Anwendung zum Absturz durch nicht abgefangene Ausnahme. Wenn Sie die Anwendung auf iOS 9, dann sehen Sie nur eine Fehlermeldung in der Konsole. Stoppen Sie am Kopf kratzen, und lassen Sie uns herausfinden, gemeinsam.

Objekt Unzugänglich

Obwohl die Anwendung stürzt auf iOS 8, die Ausgabe, die wir sehen, in der Konsole ist klar und auf den Punkt.

1
Faulting[7189:2427906] *** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x175b2ba0 <x-coredata://3920E0C9-6613-47E6-AA19-66AF6555140A/List/p1>''

Das erste, was zu bemerken ist, dass der Absturz durch eine nicht abgefangene Ausnahme. Was ist wichtiger für unsere Diskussion ist jedoch der Grund, warum die exception geworfen wurde. Core Data sagt uns, dass es nicht in der Lage war zu erfüllen, eine Schuld für eine Beziehung. Das Verhältnis Kern-Daten beziehen sich auf die Liste Beziehung des Elements, wir erschlossen, die in der Tabelle anzeigen.

Wenn Sie einen Blick auf die Umsetzung der tableView(tableView:didSelectRowAtIndexPath:), dann wirst du verstehen, warum Core Data hat eine Ausnahme ausgelöst. In dieser Methode Holen wir das Element der Benutzer abgegriffen und drucken die Namen auf der Liste auf der Konsole aus.

1
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
2
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
3
    
4
    if let item = self.fetchedResultsController.objectAtIndexPath(indexPath) as? Item {
5
        print(item.list?.name)
6
    }
7
    
8
}

Da die Liste Beziehung ist eine Schuld, die Kern-Daten muss das Feuer den Fehler zu beheben. Dies bedeutet, dass die Core-Daten, fragt der permanente Speicher für die Liste aufzuzeichnen. Das problem ist, dass der Datensatz nicht mehr in die persistente Speicherung, die ist, warum eine Ausnahme geworfen wurde.

Löschen Unzugänglich Fehler

Bis iOS 9, das war bisher immer die default-Verhalten. Wie von iOS 9, dem Kern die Daten nicht länger einen Ausnahmefehler. Stattdessen meldet es eine kryptische Nachricht auf der Konsole aus. Trotz der Meldung unklar zu sein, enthält es noch den Grund des Problems.

1
Faulting[2806:1306995] CoreData: warning: An NSManagedObjectContext delegate overrode fault handling behavior to silently delete the object with ID '0xd000000000140000 <x-coredata://396CF04E-B8B4-4108-8719-3C651F880C33/List/p5>' and substitute nil/0 for all property values instead of throwing.

Die Kernaussage ist, dass Core Data nicht länger einen Ausnahmefehler aus, wenn es nicht in der Lage ist zu erfüllen, ein Fehler. Die eigentlich gute Nachricht ist, dass Ihre Anwendung stürzt nicht mehr ab, wenn Sie nicht fangen die Ausnahme.

Der Grund für das nicht auslösen einer Ausnahme auf iOS 9 ist durch die Einführung einer neuen Immobilie, shouldDeleteInaccessibleFaults, und eine neue Methode, shouldHandleInaccessibleFault(_:forObjectID:triggeredByProperty:), auf der NSManagedObjectContext Klasse. Ich werde Sie nicht decken Sie diese Ergänzungen in diesem tutorial.

Was Sie sich merken müssen ist, dass iOS 9, standardmäßig setzt die shouldDeleteInaccessibleFaults zu wahren. Dies bedeutet, dass ein unzugängliches verwaltete Objekt wird als gelöscht markiert und dessen Eigenschaften werden gelöscht. Wenn shouldDeleteInaccessibleFaults ist auf false gesetzt, Core Data wird wieder das alte Verhalten durch das werfen einer Ausnahme.

Natürlich, die shouldDeleteInaccessibleFaults Eigentum geht hand in hand mit shouldHandleInaccessibleFault(_:forObjectID:triggeredByProperty:). Wenn Sie diese Methode überschreiben, die Sie behandeln können unzugängliche Objekte mehr aus.

Umgang Mit Störungen

Beim auftreten einer Ausnahme wegen der Core-Daten, die nicht in der Lage zu erfüllen, einen Fehler, können Sie denken, dass Core Data ist ein bisschen aggressiv. Diese Reaktion ist durchaus üblich, für Menschen, die neu auf dem Rahmen. Die Wahrheit ist, dass der Entwickler Schuld. Core Data wurde entwickelt, mit einem bestimmten Ziele im Auge, und fehlgeschlagenes ist ein wesentlicher Bestandteil um diese Ziele zu realisieren.

Trotz Ihres namens, der Fehler sollte immer fulfillable. Wenn eine Störung nicht erfüllt werden, dann das bedeutet, dass das Datenmodell nicht korrekt eingerichtet sind oder die Anwendung nicht Beachtung der Regeln, die von Core Data framework.

In der Core Data Programming Guide, Apple listet eine Reihe von Szenarien, die zu Störungen führen können nicht mehr erfüllt werden. Die häufigsten Szenarien sind falsch konfiguriert Beziehungen (Regeln löschen) und das löschen eines managed object, während die Anwendung hat immer noch einen starken Bezug auf das verwaltete Objekt.

Seien Sie gewarnt, es gibt auch andere Szenarien möglich. Aus meiner Erfahrung, Entwickler sind oft in ähnliche Probleme wegen einem problem mit der Core Data stack. Zum Beispiel, wenn die Anwendung hält eine starke Referenz auf ein verwaltetes Objekt und irgendwann freigibt die managed-object-context -, managed-object -, dann Kern-Daten ist nicht mehr in der Lage zu erfüllen, die Störungen für das verwaltete Objekt. Ich hoffe, Sie verstehen, dass dies sollte nicht passieren, wenn Sie spielen durch den Core-Daten Regeln.

Fazit

Kern-Daten, die Fehler sind unglaublich nützlich und ein wesentlicher Bestandteil der Apple-Persistenz-framework. Ich hoffe dieser Artikel hat Euch gelehrt, wie man mit Störungen und wo zu suchen, wenn Sie Störungen nicht erfüllt werden. Wenn Sie irgendwelche Fragen haben, fühlen Sie sich frei, lassen Sie Sie in den Kommentaren unten oder erreichen, um mich auf Twitter.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.