Swift + CoreData + Eine kleine Datei

    Bild

    Meine Hände kämmten hier, um herauszufinden, was für ein Tier so ein Swift war und womit es tatsächlich gegessen wurde. Wie erwartet gab es bis jetzt viele Probleme und Fallstricke, auch wenn ich nicht weiß, wie ich diesen Swift überhaupt kochen soll. Das größte Problem wartete auf mich, als ich versuchte, diese Swift mit CoreData anzufreunden - das Ding weigerte sich im Grunde zu arbeiten. Übermäßiges Googeln führte zu keinem guten Ergebnis - die Informationen waren entweder sehr fragmentarisch oder von Krücken übersät. In der ersten Nacht der Qual kapitulierte ich und entschied mich, die dümmste Lösung zu verwenden, um mit CoreData auf die alte Art und Weise zu arbeiten - den gesamten Code in dem guten alten Objective-C zu speichern und bereits von Swift darauf zuzugreifen (zum Beispiel in Interfaces). Der Perfektionismus in der Seele machte jedoch keine Pause, und es war notwendig, eine rein einsprachige Entscheidung zu treffen, die ich tatsächlich treffen konnte. obwohl gestehen, und nicht ohne Krücken auch. Wer sich für den Vorgang interessiert, frage ich nach Katze. Außerdem schlage ich vor, Fehler zu sammeln und nicht die meiner Meinung nach bequemsten Dinge, die mit der neuen Sprache einhergingen. Vielleicht habe ich etwas schief gemacht - ich bin dankbar für Kommentare und Korrekturen sowie für eine Diskussion über Best Practices.

    Wen interessiert die Zeit?


    Ohne den Artikel zu lesen, können Sie sofort ein Beispiel von https://github.com/KoNEW/CoreDataTest.git herunterladen und alles selbst rauchen.

    Synthesebeispiel


    Was werden wir auswählen

    Im Folgenden verwenden wir für die Analyse aller Probleme und Beispiele ein synthetisches Projekt - wir erstellen eine Anwendung zum Anzeigen und Verwalten der klassischen Entitäten "Abteilung" und "Mitarbeiter".

    Darüber hinaus werden wir die Abteilung mit den folgenden Feldern charakterisieren:

    • name (string - erforderlich)
    • interne Nummer (Nummer - erforderlich)
    • Telefonnummer (Zeile - optional, wir werden die Richtigkeit der Nummer nicht überprüfen)


    Und der Mitarbeiter bzw.:

    • Name (String - erforderlich)
    • Nachname (Zeichenfolge - erforderlich)
    • Geschlecht (Nummer - erforderlich)
    • Alter (Anzahl - optional)


    Datenmanager

    Der erste Schritt ist das Öffnen von Xcode und das Erstellen eines einfachen Projekts mit CoreData und dem Swift-Sprachensatz. Die einzige Bearbeitung, die wir in dieser Phase vornehmen werden, besteht darin, die gesamte Arbeit mit CoreData vom Anwendungsdelegierten auszuschneiden und an eine separate Klasse zu übertragen, die für uns als Singleton fungiert. Ich war es nur gewohnt, wenn ich Code gemacht habe, und hier wiederhole ich: Gleichzeitig können Sie sehen, wie man unter Swift einen Singleton erstellt. Das Präfix für alle unsere Klassen wird im Folgenden von CS (CoreData + Swift) verwendet.

    Pfosten Nummer 1
    Ich weiß nicht, ob dies ein Fehler in Xcode 6 Beta oder einer Funktion ist, aber die Präfixe für Ihre eigenen Klassen, damit Sie sie nicht jedes Mal schreiben, müssen Sie sie jetzt manuell festlegen. Sie können dies auf der Registerkarte Dateiinspektor tun, wenn Sie eine Projektdatei auswählen.


    Was machen wir also:
    • Schneiden Sie die gesamte Arbeit mit CoreData von AppDelegate aus
    • Erstellen Sie die CSDataManager-Klasse
    • Darin erstellen wir Eigenschaften für die Arbeit mit dem Modell, dem Kontext und dem direkten Data Warehouse.
    • Wir erstellen eine Methode für die Arbeit als Singleton


    Als Ergebnis haben wir die Datei AppDelegate.swift wie folgt:

    import UIKit
    import CoreData
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            // Override point for customization after application launch.
            return true
        }
    }
    

    Und die CSDataManager.swft-Datei lautet wie folgt:
    import UIKit
    import Foundation
    import CoreData
    let kCSErrorDomain = "ru.novilab-mobile.cstest"
    let kCSErrorLocalStorageCode = -1000
    @objc(CSDataManager)
    class CSDataManager:NSObject {
        //Managed Model
        var _managedModel: NSManagedObjectModel?
        var managedModel: NSManagedObjectModel{
            if !_managedModel{
                _managedModel = NSManagedObjectModel.mergedModelFromBundles(nil)
            }
            return _managedModel!
        }
        //Store coordinator
        var _storeCoordinator: NSPersistentStoreCoordinator?
        var storeCoordinator: NSPersistentStoreCoordinator{
            if !_storeCoordinator{
                let _storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CSDataStorage.sqlite")
                _storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedModel)
                func addStore() -> NSError?{
                    var result: NSError? = nil
                    if _storeCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: _storeURL, options: nil, error: &result) == nil{
                        println("Create persistent store error occurred: \(result?.userInfo)")
                    }
                    return result
                }
                var error = addStore()
                if  error != nil{
                    println("Store scheme error. Will remove store and try again. TODO: add scheme migration.")
                    NSFileManager.defaultManager().removeItemAtURL(_storeURL, error: nil)
                    error = addStore()
                    if error{
                        println("Unresolved critical error with persistent store: \(error?.userInfo)")
                        abort()
                    }
                }
            }
            return _storeCoordinator!
        }
        //Managed Context
        var _managedContext: NSManagedObjectContext? = nil
        var managedContext: NSManagedObjectContext {
            if !_managedContext {
                let coordinator = self.storeCoordinator
                if coordinator != nil {
                    _managedContext = NSManagedObjectContext()
                    _managedContext!.persistentStoreCoordinator = coordinator
                }
            }
            return _managedContext!
        }
        //Init
        init() {
            super.init()
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "appDidEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
        }
        @objc(appDidEnterBackground)
        func appDidEnterBackground(){
            var (result:Bool, error:NSError?) = self.saveContext()
            if error != nil{
                println("Application did not save data with reason: \(error?.userInfo)")
            }
        }
        // Returns the URL to the application's Documents directory.
        var applicationDocumentsDirectory: NSURL {
            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
            return urls[urls.endIndex-1] as NSURL
        }
        //Save context
        func saveContext() -> (Bool, NSError?){
            println("Will save")
            var error: NSError? = nil
            var result: Bool = false
            let context = self.managedContext
            if context != nil{
                if context.hasChanges && !context.save(&error){
                    println("Save context error occurred: \(error?.userInfo)")
                }else{
                    result = true
                }
            }else{
                let errorCode = kCSErrorLocalStorageCode
                let userInfo = [NSLocalizedDescriptionKey : "Managed context is nil"]
                error = NSError.errorWithDomain(kCSErrorDomain, code: errorCode, userInfo: userInfo)
            }
            return (result, error)
        }
        //Singleton Instance
        class func sharedInstance() -> CSDataManager{
            struct wrapper{
                static var shared_instance: CSDataManager? = nil
                static var token: dispatch_once_t = 0
            }
            dispatch_once(&wrapper.token, {wrapper.shared_instance = CSDataManager()})
            return wrapper.shared_instance!
        }
    }
    


    Die Basis wurde automatisch von dem Code genommen, der den Xcode generiert hat - das heißt, es kann bis zu einem gewissen Grad als Referenz betrachtet werden. Aus den interessanten Aspekten des Sprachtrainings möchte ich in dieser Datei Folgendes für mich herausgreifen:

    • arbeiten mit globalen Konstanten
    • arbeiten mit Klasseneigenschaften
    • statische Klassenmethoden (gute alte Klassenobjektmethoden)
    • gespeicherte Prozeduren (archivierte die storeCoordinator-Eigenschaft, da sie das Datenmodell in Zukunft ständig änderte und dies ein automatisches Überschreiben der Datenbankdatei sicherstellte, falls erforderlich)
    • Arbeiten mit Tuples anhand eines Beispiels für eine geänderte Methode zum Speichern des Kontexts
    • mit NSNotificationCenter arbeiten


    Pfosten Nummer 2
    Arbeiten mit Eigenschaften - ich mag es wirklich nicht. Das Beispiel basiert auf dem, was Xcode standardmäßig selbst bietet - dementsprechend komme ich zu dem Schluss, dass dies die beste der vorhandenen Lösungen ist. Ich mag es nicht besonders - die Notwendigkeit, eine interne Variable direkt für die Speicherung zu deklarieren (früher funktionierte dies unter der Haube). Darüber hinaus bleiben die Variablen selbst trotz des vorangestellten Unterstrichs von außen sichtbar - und es stellt sich heraus, dass im Dateiinspektor für jede unserer Aufgaben zwei Eigenschaften sichtbar sind. Insgesamt mag ich nicht:
    • Die Notwendigkeit, Eigenschaften explizit zu duplizieren, um solche Probleme zu lösen
    • Unfähigkeit, nur interne Variablen zu erstellen
    • Die Unmöglichkeit, interne Eigenschaften zu erstellen - bevor wir uns entschieden haben, die Eigenschaft in der Implementierungsdatei und nicht in der Beschaffungsdatei zu definieren


    Bild


    Pfosten Nummer 3
    Das Singleton-Muster wird durch eine harte Krücke unter Verwendung der internen Struktur implementiert. Theoretisch sollte dies auf einfache Weise durch die Verwendung von Klassenvariablen (class var) gelöst werden, die in der Sprachspezifikation deklariert sind - de facto wird der Compiler jedoch noch nicht unterstützt. Traurigkeit, Traurigkeit - wir warten auf Korrekturen. Auch in der aktuellen Version der Sprache ist es nach wie vor (im Vergleich zu Objective-C) unmöglich, den Klasseninitialisierer als private Methode zu kennzeichnen, wodurch es immer noch unmöglich ist, einen reinen Singleton zu erstellen, der Idioten widersteht.


    Jamb Nummer 4 oder Feature, ich weiß es nicht
    Beachten Sie auch, wie der Aufruf von NSNotificationCenter funktioniert. Es gibt einen einfachen Punkt. Apple schreibt, dass alle Systembibliotheken (UIKit, Foundation, CoreData usw.) Swift bereits erfolgreich und vollständig kennen. In Wirklichkeit ist dies jedoch nicht ganz richtig, aber nicht ganz. Unter der Haube läuft NSNotificationCenter auf reinem Objective-C, das höchstwahrscheinlich mit allem anderen in Ihrem Code kompatibel ist. Aus diesem Grund gibt es in seiner Anwendung eine Reihe von Nuancen und Einschränkungen:

    Moment eins

    Damit unser Code ordnungsgemäß mit Objective-C-Aufrufen funktioniert, müssen wir ihn kompatibel machen - hier entspricht im Allgemeinen alles den Anweisungen. Fügen Sie dem Klassennamen und den Methoden, die wir benötigen, magische Attribute hinzu. @objc() Dies ist beispielsweise ein Teil von:

    @objc(CSDataManager)
    class CSDataManager:NSObject {
    ...
    @objc(appDidEnterBackground)
    func appDidEnterBackground(){
    ...
    


    Moment zwei

    Es wäre logisch, den Aufruf von der Benachrichtigungszentrale an die saveContext-Methode selbst zu binden - aber da Tuple für uns zurückgegeben wird, können wir dies nicht tun. Solche Konstruktionen sind in Objective-C nicht definiert. Aus diesem Grund verwenden wir eine Krücke mit einem einfachen void Methodenaufruf. Im Prinzip ist alles Zen, nein, nein. Aber in Ihrem Kopf sollten solche Dinge bei der Gestaltung Ihres Produkts berücksichtigt werden.


    Erstellen Sie ein Datenmodell

    Hier ist alles trivial Standard Xcode Tools erstellen unser Datenmodell - am Ende bekommen wir so etwas.

    Bild

    Eigentlich das Problem


    Und was genau ist das Problem. Es ist ganz einfach: Die Codegenerierung für Vererbungsklassen von NSManagedObject ist in Xcode 6-Beta fehlerhaft. Genauer gesagt, der Code wird auf Objective-C und nicht auf Swift generiert, aber dies ist im Allgemeinen irgendwie nicht so einfach.
    Also, kurz, was sind die Lösungen hier nochmal:

    • Option A: Wir verwenden die normale Codegenerierung, erhalten die üblichen Objective-C-Arbeitsdateien und verwenden sie über die Bridging-Datei in unserem Haupt-Swift-Code. Informationen zur Verwendung benutzerdefinierter Objective-C-Klassen in Swift finden Sie hier - Swift und Objective-C im selben Projekt
    • Option B. Wir versuchen das Gegenteil zu erreichen - wir werden eine Swift-Klasse schreiben, die sich wie eine Objective-C-Klasse verhalten kann und gleichzeitig mit CoreData in Fremdwährung arbeitet. Nehmen Sie dazu die Datei in die rechte Hand und die extrem kurze Anleitung von Apple in die linke - Schnelle Klassen mit Objective-C-Verhalten schreiben


    Befolgen Sie die Anweisungen


    Betrachten wir zunächst die Arbeit mit nur einer Essenz der "Abteilung", und kehren wir etwas später zu den Beziehungen zurück. Befolgen Sie daher die Anweisungen von Apple Buchstabe für Buchstabe, um die CSDepartment-Klasse in dieser Datei zu beschreiben:

    import Foundation
    import CoreData
    import UIKit
    class CSDepartment : NSManagedObject{
        @NSManaged var title: NSString
        @NSManaged var internalID: NSNumber
        @NSManaged var phone: NSString?
    }
    


    Und wir werden die gesamte Arbeit mit dem Code, den ich in AppDelegate hinterlassen habe, der Einfachheit halber überprüfen (später wird übrigens die richtige Version für uns auf einem Bol geändert).

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        //Get manager
        let manager = CSDataManager.sharedInstance()
        //Create new department
        let newDepartment : AnyObject! = NSEntityDescription.insertNewObjectForEntityForName("CSDepartment", inManagedObjectContext: manager.managedContext)
        //Save context
        manager.saveContext()
        //Get and print all departments
        let request = NSFetchRequest(entityName: "CSDepartment")
        let departments = manager.managedContext.executeFetchRequest(request, error: nil)
        println("Departments: \(departments)")
        return true
    }
    


    Wir fangen an, schauen uns die Protokolle an und sind traurig. Wichtige Punkte:

    • Zunächst erhalten wir einen Fehler beim Speichern von Daten in CoreData, da eine Reihe von Feldern als obligatorisch festgelegt sind (Titel und interne ID), aber wir haben sie nicht angegeben. Hier ist eine typische Lösung, um einige Standardwerte in der Modelldatei festzulegen oder die awakeFromInsert-Methode zu verwenden. Die erste Lösung funktioniert, aber nicht sportlich, die zweite funktioniert nicht in dieser Form - die Methode wird einfach nicht aufgerufen, was mich entmutigt hat.
    • Der zweite wichtige Punkt, in den Protokollen sehen wir so etwas wie Abteilungen:
      [ (entity: CSDepartment; id: 0xb264090  ; data: {employees =     (); internalID = nil;phone = nil;title = nil;})] 
      

      Aus diesem Protokoll folgt eine wichtige Schlussfolgerung: Unsere Variable wurde als Instanz von NSManagedObject und nicht als CSDepartment instanziiert. Infolgedessen können wir auch die Werte der Felder nicht spezifizieren - da starres Typecasting im Geiste ist
      let newDepartment : CSDepartment = NSEntityDescription.insertNewObjectForEntityForName("CSDepartment", inManagedObjectContext: manager.managedContext) as CSDepartment
      

      wird nicht funktionieren, die Anwendung stürzt nur ab.


    Wir legen die Akte ein

    Nachdem ich durch das Netzwerk gewandert war, fand ich eine Reihe von Gesten, mit denen der Code funktioniert. Also, was müssen Sie tun:

    Schritt 1. Kompatibel mit Objective-C.

    Irgendwo unter der Haube führen wir wieder saubere Objective-C-Aufrufe aus, daher müssen wir unsere neue Klasse mit Objective-C-Aufrufen kompatibel machen. Wir machen das auf Kosten der Richtlinie in gewohnter Weise@objc()

    Schritt 2. Schleifen Sie die Modelldatei.

    Dies ist kein offensichtlicher Schritt - wir müssen die Datei unseres Modells erneut auswählen und in der Konfiguration des Modells Hand in Hand registrieren, welche Klasse zum Anzeigen der Entität verwendet werden soll.

    Bild

    Schritt 3. Kosmetik.

    Nach den beiden vorherigen Schritten sollte alles funktionieren, aber ich habe trotzdem die awakeFromInsert-Methode hinzugefügt, die jetzt auch funktioniert hat. Außerdem hat er eine Beschreibungsmethode hinzugefügt, damit eine schönere und verständlichere Datenzeile im Protokoll angezeigt wird.

    Infolgedessen sah der Code unserer Klasse allmählich so aus:

    import Foundation
    import CoreData
    import UIKit
    @objc(CSDepartment)
    class CSDepartment : NSManagedObject{
        @NSManaged var title: NSString
        @NSManaged var internalID: NSNumber
        @NSManaged var phone: NSString?
        override func awakeFromInsert() {
            self.title = "New department"
            self.internalID = 0
        }
        func description() -> NSString{
            return "Department: className=\(self.dynamicType.description()), title=\(self.title), id=[\(self.internalID)] and phone=\(self.phone)"
        }
    }
    


    Wir führen unsere Tests erneut durch - alles funktioniert, Sie können sich freuen.

    Mit Beziehungen arbeiten


    Also mit trivialen Entitäten aussortiert. Analog können Sie eine Beschreibung der Entität vornehmen CSEmployee. Sie müssen nur noch eines tun - damit unser System ordnungsgemäß mit Entitäten funktioniert -, um Verbindungen hinzufügen und entfernen zu können. Die Beziehung zwischen der Abteilung und unseren Mitarbeitern ist eins zu viele. Hier haben sich die neue Sprache und Xcode auf zwei Arten verhalten.
    Um die Kommunikation zwischen dem Mitarbeiter und der Abteilung zu implementieren, stellte sich heraus, dass alles trivial war. Fügen Sie der Liste der Eigenschaften, die auf die Abteilung selbst verweisen, einfach eine weitere hinzu. Insgesamt sah unsere Mitarbeiterklasse so aus (ich habe die zufällige Generierung von Vor- und Nachnamen aus globalen Arrays von mir selbst hinzugefügt):

    import Foundation
    import CoreData
    let st_fNames = ["John", "David", "Michael", "Bob"]
    let st_lNames = ["Lim", "Jobs", "Kyler"]
    @objc(CSEmployee)
    class CSEmployee:NSManagedObject{
        @NSManaged var firstName: NSString
        @NSManaged var lastName: NSString
        @NSManaged var age: NSNumber?
        @NSManaged var department: CSDepartment
        override func awakeFromInsert() {
            super.awakeFromInsert()
            self.firstName = st_fNames[Int(arc4random_uniform(UInt32(st_fNames.count)))]
            self.lastName = st_lNames[Int(arc4random_uniform(UInt32(st_lNames.count)))]
        }
        func description() -> NSString{
            return "Employee: name= \(self.firstName) \(self.lastName), age=\(self.age) years" 
        }
    }
    


    Um die Unterstützung des Mechanismus auf der Seite der Abteilung zu implementieren, musste ich die Datei stärker in die Hand nehmen - da wiederum aufgrund der fehlerhaften Codegenerierung keine magischen Methoden zum Hinzufügen von Kindern erstellt wurden. Insgesamt machen wir folgendes:

    • Fügen Sie eine Eigenschaft hinzu, um Mitarbeiter mit der NSSet-Klasse zu speichern
    • Hinzufügen benutzerdefinierter Methoden zum Hinzufügen und Entfernen von Mitarbeitern - basierend auf Xcode-Snippets für die Objective-C-Version


    Als Ergebnis begann unsere Klasse so auszusehen:

    import Foundation
    import CoreData
    @objc(CSDepartment)
    class CSDepartment : NSManagedObject{
        @NSManaged var title: NSString
        @NSManaged var internalID: NSNumber
        @NSManaged var phone: NSString?
        @NSManaged var employees: NSSet
        override func awakeFromInsert() {
            self.title = "New department"
            self.internalID = 0
        }
        func description() -> NSString{
            let employeesDescription = self.employees.allObjects.map({employee in employee.description()})
            return "Department: title=\(self.title), id=[\(self.internalID)], phone=\(self.phone) and employees = \(employeesDescription)"
        }
        //Working with Employees
        func addEmployeesObject(employee: CSEmployee?){
            let set:NSSet = NSSet(object: employee)
            self.addEmployees(set)
        }
        func removeEmployeesObject(employee: CSEmployee?){
            let set:NSSet = NSSet(object: employee)
            self.removeEmployees(set)
        }
        func addEmployees(employees: NSSet?){
            self.willChangeValueForKey("employees", withSetMutation: NSKeyValueSetMutationKind.UnionSetMutation, usingObjects: employees)
            self.primitiveValueForKey("employees").unionSet(employees)
            self.didChangeValueForKey("employees", withSetMutation: NSKeyValueSetMutationKind.UnionSetMutation, usingObjects: employees)
        }
        func removeEmployees(employees: NSSet?){
            self.willChangeValueForKey("employess", withSetMutation: NSKeyValueSetMutationKind.MinusSetMutation, usingObjects: employees)
            self.primitiveValueForKey("employees").minusSet(employees)
            self.didChangeValueForKey("employees", withSetMutation: NSKeyValueSetMutationKind.MinusSetMutation, usingObjects: employees)
        }
    }
    


    Endgültiger Bestätigungscode und verbleibende Probleme


    Letztendlich wurden folgende Anpassungen vorgenommen:
    • Die CSDataManager-Klasse wurde um zwei Methoden erweitert, um eine vollständige Liste der Abteilungen und Mitarbeiter zu erhalten
    • Beispielcode geändert - Funktionen zum Hinzufügen, Löschen von Objekten und Kaskadenlöschen wurden untersucht


    Also, der resultierende AppDelegate-Code:

    import UIKit
    import CoreData
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var window: UIWindow?
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            //Get manager
            let manager = CSDataManager.sharedInstance()
            //Testing insert new objects
            let newDepartment : CSDepartment = NSEntityDescription.insertNewObjectForEntityForName("CSDepartment", inManagedObjectContext: manager.managedContext) as CSDepartment
            let newEmployee: CSEmployee = NSEntityDescription.insertNewObjectForEntityForName("CSEmployee", inManagedObjectContext: manager.managedContext) as CSEmployee
            let newEmployee2: CSEmployee = NSEntityDescription.insertNewObjectForEntityForName("CSEmployee", inManagedObjectContext: manager.managedContext) as CSEmployee
            newEmployee.department = newDepartment
            newDepartment.addEmployeesObject(newEmployee2)
            manager.saveContext()
            //Get and print all departments
            println("Have add oen department and two employees")
            println("Departments: \(manager.departments())")
            println("Employees: \(manager.employees())")
            //Testing remove child object
            newDepartment.removeEmployeesObject(newEmployee2)
            manager.saveContext()
            println("Have delete one employee")
            println("Departments: \(manager.departments())")
            //Testing cascade remove
            manager.managedContext.deleteObject(newDepartment)
            manager.saveContext()
            println("\nHave delete department")
            println("Departments: \(manager.departments())")
            println("Employees: \(manager.employees())")
            //Uncomment to remove all records
    //        let departments = manager.departments()
    //        for i in 0..departments.count{
    //            let dep = departments[i] as CSDepartment
    //            manager.managedContext.deleteObject(dep)
    //        }
    //        let employees = manager.employees()
    //        for i in 0..employees.count{
    //            let emp = employees[i] as CSEmployee
    //            manager.managedContext.deleteObject(emp)
    //        }
    //        manager.saveContext()
    //        println("\nHave delete all data")
    //        println("Departments: \(manager.departments())")
    //        println("Employees: \(manager.employees())")
            return true
        }
    }
    


    Es wurde ein schwerwiegender Fehler gefunden: Das kaskadierende Löschen von Objekten erfolgt mit einem Knall. Wenn jedoch Mitarbeiter aus der Abteilung mithilfe von Methoden removeEmployeesObject и removeEmployeesfür untergeordnete Objekte gelöscht werden, werden keine Zeiger auf die Abteilung zurückgesetzt, und dementsprechend werden Objekte vom System im Speicher noch gestohlen.
    UPDATE: Dies ist kein Fehler - Objective-C-Code verhält sich genauso, anscheinend bin ich etwas verwirrend. Offensichtlich sollten diese Probleme durch einen architektonischen Ansatz gelöst werden.

    Fazit


    Im Allgemeinen können Sie arbeiten, aber nicht ohne Schmerzen in der Seele. Sie müssen die Datei immer griffbereit halten. Ich freue mich über Kommentare, Änderungsanträge und freie Diskussionen auf der Suche nach dem wahren Weg der Samurai.

    Jetzt auch beliebt: