iOS9 Xcode 7 - 核心数据 - 避免重复的对象

nik*_*nov 8 xcode ios swift ios9 swift2

如WWDC2015 演示视频中所述,在新的Xcode7中,我们可以直接在Xcode模型编辑器中设置对象的唯一性.我试图实现我的代码,但有些东西没有按预期工作.当我尝试保存重复的对象时,Xcode拒绝保存,但表更新了重复的单元格.

所以我设置了startdate和enddate的唯一属性.

在此输入图像描述

然后我修改了我的保存功能来处理错误并通过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)
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好,但是当我使用取消按钮返回根控制器时,表格会显示更新的重复单元格.

@IBAction func cancelButtonPressed(sender: UIBarButtonItem) {
    self.navigationController?.popToRootViewControllerAnimated(true)
}
Run Code Online (Sandbox Code Playgroud)

此外,停止并运行应用程序将删除重复项.

这是一个有问题的行为的视频.

生成的错误如下:

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.
Run Code Online (Sandbox Code Playgroud)

修复addContract()以修复问题如下:

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)

    }
}
Run Code Online (Sandbox Code Playgroud)

Lom*_*baX 5

你用a NSFetchedResultsController来显示数据吗?

似乎只有在保存时才能确保唯一性.但是Core Data仍然允许您在执行时将对象插入到NSManagedObjectContext:

let newContractData = Contract(entity: entity!, insertIntoManagedObjectContext: context)
Run Code Online (Sandbox Code Playgroud)

保存时,保存操作失败,但对象仍在上下文中,因此NSFetchedResultsController仍然显示它.

尝试从catch代码中的上下文中删除对象:

context.deleteObject(newContractData)
Run Code Online (Sandbox Code Playgroud)