防止在CoreData中保存重复值

时间:2019-07-18 00:57:47

标签: swift core-data nspredicate

我正尝试在下面使用此方法来保存或创建GameMO对象,该对象是NSManagedObject的子类。问题是,当我在更改winnerChanged()的选定值时调用下面的UISegmentedControl方法时,在下面调用了此saveOrCreateGameMO()方法,最终创建了一个新的GameMO对象,存储在CoreData而不是加载已经存在于CoreData中的一个并对其进行更新。我不知道为什么会这样。这是我更改游戏获胜者时在日志中看到的内容:

Saving game because winner was changed
Updating Game to CoreData

这告诉我游戏正在尝试更新已经存在的GameMO对象,因为NSPredicate中的FetchRequest评估为true,并在CoreData中找到至少一个具有相同{{ 1}}(只是一个随机的UUID字符串),并且正在使用它而不是创建一个新的字符串。

更令人困惑的是,我第一次运行我的应用程序(将其从模拟器中完全删除以重置CoreData的持久性存储后),它从id和{中弹出Updating Conference to CoreDataUpdating Team to CoreData {1}},表明它已经以某种方式找到了saveOrCreateConference()这样的NSPredicate有效值。如果清除了持久存储,怎么可能?我还在下面介绍了如何加载游戏。

saveOrCreateTeam()
NSPredicate(format: "name == %@", teamMO.name)
@IBAction func winnerChanged(_ sender: UISegmentedControl) {
        os_log("Saving game because winner was changed", type: .debug)
        let viewcell = sender.superview?.superview as? ConferenceGamesTableViewCell
        guard viewcell != nil else {
            os_log("viewcell is nil in winnerChanged in ConferenceGamesTableViewController", type: .debug)
            return
        }
        guard let game = viewcell?.game else {
            os_log("Could not unwrap game in winnerChanged in ConferenceGamesTableViewController", type: .debug)
            return
        }
        guard let winnerName = sender.titleForSegment(at: sender.selectedSegmentIndex) else {
            os_log("Could not unwrap game winner from UISegmentedControl in ConferenceGamesTableViewController", type: .debug)
            return
        }
        guard let winnerConferenceName = Conference.name(forTeamName: winnerName) else {
            os_log("Could not unwrap game winner conference name in ConferenceGamesTableViewController", type: .debug)
            return
        }
        game.winner = Team(teamName: winnerName, conferenceName: winnerConferenceName)
        guard let gameMO = GameMO.newGameMO(fromGame: game) else {
            os_log("Could not unwrap gameMO from game in ConferenceGamesTableViewController", type: .debug)
            return
        }

        let dataModelManager = DataModelManager.shared
        dataModelManager.saveOrCreateGameMO(gameMO: gameMO)
    }
public func saveOrCreateGameMO(gameMO: GameMO) {

        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            return
        }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "GameMO")
        fetchRequest.predicate = NSPredicate(format: "id == %@", gameMO.id)

        do {
            let test = try managedContext.fetch(fetchRequest)

            let objectUpdate = test[0] as! GameMO
            objectUpdate.setValue(gameMO.id, forKey: "id")
            objectUpdate.setValue(gameMO.conferencesNames, forKeyPath: "conferencesNames")
            objectUpdate.setValue(gameMO.confidence, forKeyPath: "confidence")
            objectUpdate.setValue(gameMO.contestantsNames, forKeyPath: "contestantsNames")
            objectUpdate.setValue(gameMO.winnerName, forKeyPath: "winnerName")

            do {
                try managedContext.save()
                os_log("Updating Game to CoreData", type: .debug)
            } catch let error as NSError {
                print("Could not update game to CoreData. \(error), \(error.userInfo)")
            }
        } catch {
            os_log("Could not fetch game from CoreData. Saving it as a new game.", type: .debug)

            let entity = NSEntityDescription.entity(forEntityName: "Game", in: managedContext)!
            let newGameMO = GameMO(entity: entity, insertInto: managedContext)

            newGameMO.setValue(gameMO.id, forKey: "id")
            newGameMO.setValue(gameMO.conferencesNames, forKeyPath: "conferencesNames")
            newGameMO.setValue(gameMO.confidence, forKeyPath: "confidence")
            newGameMO.setValue(gameMO.contestantsNames, forKeyPath: "contestantsNames")
            newGameMO.setValue(gameMO.winnerName, forKeyPath: "winnerName")

            do {
                try managedContext.save()
            } catch let error as NSError {
                print("Could not save new game to CoreData. \(error), \(error.userInfo)")
            }
        }

    }

0 个答案:

没有答案