iOS swift应用程序中Core Data的奇怪行为

Posted

技术标签:

【中文标题】iOS swift应用程序中Core Data的奇怪行为【英文标题】:Strange behavior from Core Data in iOS swift app 【发布时间】:2015-02-12 21:28:51 【问题描述】:

我正在为实体分配非零值,保存它们,然后立即检索它们。但是值返回为零。这是 Xcode 上的 ios 8.1 和 Swift(最新 GA 版本),在模拟器和设备上具有相同的行为。

我有三个实体:MatchScoreTeam。每个Match 有两个团队,team1team2Score 也有 team1team2MatchScore 具有 1x1 关系,字段分别为 betbetForMatch 由其字段 matchNumber 标识。

所以我有以下代码:

    var match:CBMatch?
    var betCard:CBScore?
    for matchNum in 1...42 
        match = CBMatch.lookup(self.managedObjectContext!, matchNumber: matchNum)

        betCard = CBScore.addForBet(self.managedObjectContext!, match: match!)

        betCard!.team1 = match!.team1
        betCard!.team2 = match!.team2

        match!.bet = betCard!

        println("For match \(matchNum), \(betCard!.team1.shortname) vs \(betCard!.team2.shortname)")
        // This is fine for all matchNum values
    

    // Verify
    if true 
        var err:NSError? = nil
        self.managedObjectContext!.save(&err)
        if err != nil 
            abort() // Hasn't happened yet
        
        match = CBMatch.lookup(self.managedObjectContext!, matchNumber: 1)
        betCard = match!.bet

        println("For match 1, \(betCard!.team1.shortname) vs \(betCard!.team2.shortname)")
     // Crashes with NPE
    // It complains that betCard!.team2 is nil but betCard!.team1 is fine
    

基本上尝试检索我刚刚设置的信息返回为零。

CBMatch:lookupCBScore:addForBet 是微不足道的:

class func lookup(moc: NSManagedObjectContext, matchNumber: Int) -> CBMatch? 
    var fetchRequest = NSFetchRequest(entityName: "CBMatch")
    var predicate = NSPredicate(format: "matchNumber == %d", matchNumber)
    fetchRequest.fetchLimit = 1
    fetchRequest.predicate = predicate
    //        fetchRequest.returnsObjectsAsFaults = false
    // With or without didn't make a difference
    var err:NSError? = nil
    let matches = moc.executeFetchRequest(fetchRequest, error: &err)!

    if matches.count == 1 && err == nil 
        let fetchedMatch = matches[0] as CBMatch
        return fetchedMatch
    
    println("Could not find match \(matchNumber)")
    return nil



class func addForBet(moc: NSManagedObjectContext, match:CBMatch) -> CBScore 
    var entity = NSEntityDescription.insertNewObjectForEntityForName("CBScore", inManagedObjectContext: moc) as CBScore

    entity.betFor = match
    return entity

我不能通过简单地丢弃 bet.team1 等来简化数据模型,因为在某些情况下 bet.team1 和 match.team1 会不同,我需要能够比较它们。对于这种(最简单的)情况,它们是相同的,因为这是第一次初始化 Score 对象。

我尝试了几件事,包括在获取期间返回ObjectsAsFault = false 等。当我使用 sqlite3 打开 .sqlite 文件时,我可以看到正在创建的条目。我尝试使用设置为 3 的 sql 调试标志,但没有跳出。我不是说这条大道已经枯竭,但我肯定是。

对这里可能发生的事情有什么想法吗?我在这个问题上停留了很长一段时间,任何想法都将不胜感激。

错误是EXC_BAD_ACCESS,问题是match.bet.team1 是 nil 。这与我在上面几行刚完成的任务相同。

【问题讨论】:

错误是什么?发布产生错误的代码。 您仍然没有发布产生错误的代码。 我更新了原帖以反映发生错误的代码。 也许你必须使用match.bet.team1.description 进行字符串插值。 我认为你应该提供你的真实代码,而不是伪代码(除非你认为问题出在 Core Data 上,这不太可能......) 【参考方案1】:

在我看来,您的数据模型存在缺陷。您将每个团队引用两次,这实际上是没有必要的。 Bet 实体不需要了解团队,因为它与Match 实体具有一对一的关系。 Bet 可以包含类似于firstValuesecondValue 的内容。

虽然理论上您的设置也应该有效,但您引入了不必要的复杂性。你没有提供足够的信息来解决你的错误,但我认为甚至没有必要费心去寻找那个错误。

只需使用match.team1 而不是match.bet.team1

顺便说一句,要注意的显而易见的事情是matchnilscorenil,或者match.team1nil - 在所有情况下score.team1 也是@987654335 @。

【讨论】:

Match.team1 和 Score.team1 很可能不同,其中一个或两个都可能为 nil。根据程序的状态,将使用正确的程序。在这个特定(最简单)的情况下,它们彼此相同,但在其他情况下,它们会有所不同。 再一次,我仍然认为这是一个设计缺陷。想想如何消除这种冗余。在我修改后的答案中查看更多明显的故障排除提示。 这不是冗余。我更新了我的文字以反映,希望这是有道理的。但是暂时忘记设计,什么会导致核心数据在保存期间不报告错误,但在保存后不立即返回保存的值?这是我的主要问题。 查看我修改后的答案。如果该属性是可选的,则可以为 nil。 但这就是问题所在 - 我专门将这些属性设置为非零值,当我读回团队时,它们返回为零。为什么会这样?我更改了我的问题以提供更多信息,请重新阅读问题说明。【参考方案2】:

在我的代码中发现了错误 - team1 和 team2 的关系是 1:1,但为了允许多次分配,它们需要是 1:N。

【讨论】:

以上是关于iOS swift应用程序中Core Data的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

(iOS Swift) 从 Core Data 获取记录返回致命错误或 nil

Swift - 如何检查现有的 Core Data Store iOS

如何正确设置 Core Data Stack 到 iOS 和 Swift 中的第一个视图控制器?

如何在 Core Data iOS Swift 中删除和更新结构类型数组?

iOS Swift Core Data 生成带有项目命名空间的 NSManagedObject

IOS Swift Core Data如何在propertiesToFetch中添加不在propertiesToGroupBy中的字段