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 版本),在模拟器和设备上具有相同的行为。
我有三个实体:Match
、Score
和 Team
。每个Match
有两个团队,team1
和team2
。 Score
也有 team1
和 team2
。 Match
与 Score
具有 1x1 关系,字段分别为 bet
和 betFor
。 Match
由其字段 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:lookup
和 CBScore: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
可以包含类似于firstValue
和secondValue
的内容。
虽然理论上您的设置也应该有效,但您引入了不必要的复杂性。你没有提供足够的信息来解决你的错误,但我认为甚至没有必要费心去寻找那个错误。
只需使用match.team1
而不是match.bet.team1
。
顺便说一句,要注意的显而易见的事情是match
是nil
,score
是nil
,或者match.team1
是nil
- 在所有情况下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中的字段