2015-06-14 12 views
8

Wie im WWDC2015 presentation video beschrieben, können wir im neuen Xcode7 die Objekteindeutigkeit direkt im Xcode Model Editor einstellen. Ich habe versucht, meinen Code zu implementieren, aber etwas funktioniert nicht wie erwartet. Wenn ich versuche, dupliziertes Objekt zu speichern, weist Xcode die Sicherung zurück, aber die Tabelle wird mit der duplizierten Zelle aktualisiert.iOS9 Xcode 7 - Core Data - Vermeidung duplizierter Objekte

Also habe ich die einzigartigen Attribute Startdatum und Enddatum festgelegt.

enter image description here

Dann Funktion Ich habe meine speichern modifiziert, um den Fehler zu behandeln und den Benutzer durch UIAlertController informieren.

func addContract() { 
    do { 
     let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
     let context: NSManagedObjectContext = appDelegate.managedObjectContext 

     let entity = NSEntityDescription.entityForName("Contract", inManagedObjectContext: context) 
     let newContractData = Contract(entity: entity!, insertIntoManagedObjectContext: context) 

     newContractData.startdate = dateFormatter.dateFromString(startDateTextField.text!)! 
     newContractData.enddate = dateFormatter.dateFromString(endDateTextField.text!)! 
     newContractData.ship = shipNameTextField.text! 
     newContractData.position = positionOnBoardTextField.text! 
     newContractData.workingdays = Int(workingDaysLabel.text!)! 

     try context.save() 
    } catch { 
     let alertController = UIAlertController(
      title: "Error", 
      message: "The contract exsist", 
      preferredStyle: UIAlertControllerStyle.Alert) 
     let okAction = UIAlertAction(
      title: "OK", 
      style: UIAlertActionStyle.Cancel, 
      handler: nil) 
     alertController.addAction(okAction) 
     presentViewController(alertController, animated: true, completion: nil) 
    } 
} 

So weit so gut, aber wenn ich mit der Löschtaste auf die Root-Controller zurück, erscheint die Tabelle mit doppelter Zelle aktualisiert.

@IBAction func cancelButtonPressed(sender: UIBarButtonItem) { 
    self.navigationController?.popToRootViewControllerAnimated(true) 
} 

Darüber hinaus stoppen und Ausführen der Anwendung entfernt die Duplikate.

Hier ist es eine video des problematischen Verhaltens.

Der erzeugte Fehler ist wie folgt:

Error Domain=NSCocoaErrorDomain Code=1551 "The operation couldn’t be completed. (Cocoa error 1551.)" UserInfo=0x7fc02d462190 {Conflicts=(
     { 
     constraint =   (
      startdate, 
      enddate 
     ); 
     entity = Contract; 
     objects =   (
      "<Contract: 0x7fc02d45ba60> (entity: Contract; id: 0x7fc02d019430 <x-coredata:///Contract/t0897571B-200B-4F04-AF87-D50831E2DE672> ; data: {\n enddate = \"2017-06-13 21:00:00 +0000\";\n position = test;\n ship = test;\n startdate = \"2016-06-13 21:00:00 +0000\";\n workingdays = 366;\n})", 
      "<Contract: 0x7fc02b7433c0> (entity: Contract; id: 0xd000000000100000 <x-coredata://C3318932-BEDB-4AB6-A856-103F542BCF44/Contract/p4> ; data: {\n enddate = \"2017-06-13 21:00:00 +0000\";\n position = test;\n ship = test;\n startdate = \"2016-06-13 21:00:00 +0000\";\n workingdays = 366;\n})" 
     ); 
    } 
)} 
2015-06-14 19:54:15.880 WorkingDays[6028:2219449] popToViewController:transition: called on <UINavigationController 0x7fc02c007e00> while an existing transition or presentation is occurring; the navigation stack will not be updated. 

Die Modifizierung von addContract(), um das Problem zu beheben wie folgt lautet:

func addContract() { 
    let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
    let context: NSManagedObjectContext = appDelegate.managedObjectContext 

    let entity = NSEntityDescription.entityForName("Contract", inManagedObjectContext: context) 
    let newContractData = Contract(entity: entity!, insertIntoManagedObjectContext: context) 
    do { 
     newContractData.startdate = dateFormatter.dateFromString(startDateTextField.text!)! 
     newContractData.enddate = dateFormatter.dateFromString(endDateTextField.text!)! 
     newContractData.ship = shipNameTextField.text! 
     newContractData.position = positionOnBoardTextField.text! 
     newContractData.workingdays = Int(workingDaysLabel.text!)! 

     try context.save() 

    } catch { 
     let alertController = UIAlertController(
      title: "Error", 
      message: "The contract exsist", 
      preferredStyle: UIAlertControllerStyle.Alert) 
     let okAction = UIAlertAction(
      title: "OK", 
      style: UIAlertActionStyle.Cancel, 
      handler: nil) 
     alertController.addAction(okAction) 
     presentViewController(alertController, animated: true, completion: nil) 

     context.deleteObject(newContractData) 
     print(error) 

    } 
} 
+1

es nützlich wäre, nur relevante Informationen zu zeigen. Und aus dem Video sah es so aus, als ob das einzige, was Sie tun müssten, ist, welches Attribut (s) eindeutig ist und die Kerndaten sich um alles kümmern. Wir können nicht sehen, ob Sie das mit diesen Codes getan haben. – Eendje

+0

Vielen Dank für die Antwort. War ein bisschen selbstsüchtig zu erwarten, dass jemand durch den ganzen Code scrollt, um mir mit dem Problem zu helfen. – nikolayDudrenov

Antwort

5

Sind Sie mit einem NSFetchedResultsController die Daten zu zeigen?

Es scheint, dass die Eindeutigkeit nur beim Speichern gewährleistet ist. Aber Core Data ermöglicht noch das Objekt in die NSManagedObjectContext einzufügen, wenn Sie tun:

let newContractData = Contract(entity: entity!, insertIntoManagedObjectContext: context) 

Wenn Sie speichern, schlägt der Sicherungsoperationen, aber das Objekt ist immer noch im Rahmen, so dass die NSFetchedResultsController noch zeigt sie an.

Versuchen Sie das Objekt aus dem Kontext, in Ihrem Fang Code zu entfernen:

context.deleteObject(newContractData) 
+0

Danke für die Antwort. Ich habe das obige versucht, funktioniert aber nicht. – nikolayDudrenov

+0

Eigentlich funktioniert, aber nur die Zeile für appDelegate, Kontext, Entität und newContractData vor dem do { – nikolayDudrenov

+0

Dies scheint normal, da die Bereiche von Do und Catch unterschiedlich sind. Daher werden Variablen, die im Do-Bereich definiert sind, nicht im Catch angezeigt. Sie haben das Richtige getan, indem Sie die Variablendeklaration in den äußeren Bereich verschoben haben – LombaX