2015-06-14 12 views
8

Zgodnie z opisem w WWDC2015 presentation video, w nowym Xcode7 możemy ustawić unikalność obiektów bezpośrednio w edytorze modeli Xcode. Próbowałem zaimplementować to mój kod, ale coś nie działa zgodnie z oczekiwaniami. Kiedy próbuję zapisać zduplikowany obiekt, Xcode odrzuca zapis, ale tabela aktualizuje się z powieloną komórką.iOS9 Xcode 7 - Podstawowe dane - unikanie duplikowania obiektów

Ustawiłem więc unikalne atrybuty startdate i enddate.

enter image description here

Potem zostały zmodyfikowane mój zapisać funkcję obsługi błędu i informuje użytkownika o 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) 
    } 
} 

Jak na razie dobrze, ale kiedy wrócę do kontrolera głównego z przycisku Anuluj, tabela wydaje na bieżąco z duplikatu komórce.

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

Ponadto zatrzymać i uruchomić aplikację usuwa duplikaty.

Oto problem z zachowaniem się.

Wygenerowany błędu jest następująca:

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. 

modyfikacja addContract(), aby rozwiązać ten problem jest następujący:

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

To byłoby przydatne, aby pokazać tylko istotne informacje. A z wideo wyglądało na to, że jedyne, co musisz zrobić, to ustawić, które atrybuty są unikatowe, a najważniejsze dane zajmą się wszystkim. Nie widzimy, czy zrobiłeś to z tymi kodami. – Eendje

+0

Dziękuję za odpowiedź. Byłem trochę samolubny oczekiwać, że ktoś przewinie cały kod, aby pomóc mi rozwiązać problem. – nikolayDudrenov

Odpowiedz

5

Używasz NSFetchedResultsController pokazać dane?

Wydaje się, że wyjątkowość jest zapewniona tylko podczas zapisywania. Ale Rdzeń danych nadal pozwala wstawić obiekt w NSManagedObjectContext kiedy to zrobić:

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

Po zapisaniu, operacje zapisać się nie powiedzie, ale obiekt jest nadal w kontekście tak NSFetchedResultsController nadal wyświetla je.

Spróbuj usunąć obiekt z kontekstu, w kodzie haczyk:

context.deleteObject(newContractData) 
+0

Dzięki za odpowiedź. Próbowałem powyższych, ale nie działa. – nikolayDudrenov

+0

Właściwie działa, ale tylko wstaw linię dla appDelegate, context, entity i newContractData przed { – nikolayDudrenov

+0

. Wydaje się to normalne, ponieważ zakresy działania i catch są różne. Więc zmienne zdefiniowane w zakresie działania nie mogą być widoczne w haczyku. Postąpiłeś słusznie, przenosząc deklarację zmiennych w zewnętrznym zakresie – LombaX

Powiązane problemy