2015-06-14 2 views
8

Come descritto in WWDC2015 presentation video, nel nuovo Xcode7 è possibile impostare l'univocità degli oggetti direttamente nell'editor del modello Xcode. Stavo cercando di implementare questo mio codice, ma qualcosa non funziona come previsto. Quando provo a salvare l'oggetto duplicato, Xcode rifiuta il salvataggio, ma la tabella si aggiorna con la cella duplicata.iOS9 Xcode 7 - Dati principali - evitare oggetti duplicati

Quindi ho impostato gli attributi univoci startdate e enddate.

enter image description here

Poi ho modificato la mia funzione di salvataggio per gestire l'errore e informare l'utente UIAlertController.

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) 
    } 
} 

Fin qui tutto bene, ma quando torno al controller radice con il pulsante di annullamento, la tabella appare aggiornato con cella duplicato.

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

Inoltre, interrompere ed eseguire l'applicazione rimuove i duplicati.

Qui è un video del comportamento problematico.

L'errore generato è il seguente:

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. 

La modifica della addContract() per risolvere il problema è il seguente:

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

sarebbe utile per visualizzare solo le informazioni rilevanti. E dal video, sembrava che l'unica cosa che dovevi fare era impostare quale attributo (i) è unico e i dati di base si occuperanno di tutto. Non possiamo vedere se lo hai fatto con questi codici. – Eendje

+0

Grazie per la risposta. Era un po 'egoista aspettarsi che qualcuno scorresse attraverso l'intero codice per aiutarmi con il problema. – nikolayDudrenov

risposta

5

Si sta utilizzando un NSFetchedResultsController per visualizzare i dati?

Sembra che l'unicità sia garantita solo quando si salva. Ma Core Data permette ancora di inserire l'oggetto nel NSManagedObjectContext quando si esegue:

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

Quando si salva, le operazioni di salvataggio fallisce, ma l'oggetto è ancora nel contesto, in modo che il NSFetchedResultsController visualizza ancora.

tenta di rimuovere l'oggetto dal contesto nel codice fermo:

context.deleteObject(newContractData) 
+0

Grazie per la risposta. Ho provato quanto sopra, ma non funziona. – nikolayDudrenov

+0

Attualmente funziona, ma solo di mettere la riga per appDelegate, context, entity e newContractData prima del do { – nikolayDudrenov

+0

Questo sembra normale poiché gli ambiti di do e catch sono diversi. Quindi le variabili definite nello scope do non possono essere viste nel catch. Hai fatto la cosa giusta spostando la dichiarazione delle variabili nello scope esterno – LombaX