使用 CoreData 获取时崩溃
Posted
技术标签:
【中文标题】使用 CoreData 获取时崩溃【英文标题】:Crash when fetching with CoreData 【发布时间】:2017-07-18 15:04:36 【问题描述】:我的应用正在生产中,当我尝试将 festRequest 的第一个元素转换为某个实体时,我在 Crashlytics 上遇到了一些崩溃。无论我多么努力,我都无法重现此崩溃。
static func getSettings() -> NotificationSettingsMO
var settings: NotificationSettingsMO!
let moc = DataController.shared.managedObjectContext
moc.performAndWait
do
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "NotificationSettings")
settings = try moc.fetch(fetchRequest).first as! NotificationSettingsMO
catch
print(error)
return settings
当尝试将请求的第一个元素转换为 NotificationSettingsMO 时发生崩溃,我确定实体存在,因为我在创建用户时创建了它。这也只发生在一小部分用户身上,但由于它使应用程序崩溃,我想尝试找出导致它的原因。
编辑:我已附上崩溃日志
Crashed: com.apple.main-thread
0 MyApp 0x100073360 specialized static NotificationSettingsMO.(getSettings() -> NotificationSettingsMO).(closure #1) (NotificationSettingsMO.swift:25)
1 MyApp 0x10007309c partial apply for static NotificationSettingsMO.(getSettings() -> NotificationSettingsMO).(closure #1) (NotificationSettingsMO.swift)
2 CoreData 0x18311d08c developerSubmittedBlockToNSManagedObjectContextPerform + 196
3 CoreData 0x18311cf54 -[NSManagedObjectContext performBlockAndWait:] + 220
4 MyApp 0x100072fa8 specialized static NotificationSettingsMO.getSettings() -> NotificationSettingsMO (NotificationSettingsMO.swift)
5 MyApp 0x1000d6190 AppDelegate.getDataOnLaunch() -> () (AppDelegate.swift)
6 MyApp 0x1000da4bc specialized AppDelegate.application(UIApplication, didFinishLaunchingWithOptions : [UIApplicationLaunchOptionsKey : Any]?) -> Bool (AppDelegate.swift:99)
7 MyApp 0x1000d3eb8 @objc AppDelegate.application(UIApplication, didFinishLaunchingWithOptions : [UIApplicationLaunchOptionsKey : Any]?) -> Bool (AppDelegate.swift)
8 UIKit 0x1863f29c0 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 400
9 UIKit 0x186622184 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2904
10 UIKit 0x1866265f0 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1684
11 UIKit 0x186623764 -[UIApplication workspaceDidEndTransaction:] + 168
12 FrontBoardServices 0x182bbf7ac __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 36
13 FrontBoardServices 0x182bbf618 -[FBSSerialQueue _performNext] + 168
14 FrontBoardServices 0x182bbf9c8 -[FBSSerialQueue _performNextFromRunLoopSource] + 56
15 CoreFoundation 0x1811d509c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
16 CoreFoundation 0x1811d4b30 __CFRunLoopDoSources0 + 540
17 CoreFoundation 0x1811d2830 __CFRunLoopRun + 724
18 CoreFoundation 0x1810fcc50 CFRunLoopRunSpecific + 384
19 UIKit 0x1863eb94c -[UIApplication _run] + 460
20 UIKit 0x1863e6088 UIApplicationMain + 204
21 MyApp 0x10001ee18 main (Measurement+Network.swift:26)
22 libdispatch.dylib 0x180c9a8b8 (Missing)
【问题讨论】:
您也可以发布崩溃日志吗?堆栈跟踪肯定有助于弄清楚到底发生了什么。 考虑如果您的 fetch 请求返回 0 个结果会发生什么。 “我在 Crashlytics 上遇到过几次崩溃”你能附上崩溃报告吗? 我忘记了所需的调用,但 Crashlytics 能够记录将包含在崩溃报告中的消息。我建议使用此功能来记录获取请求的结果,因为它很可能是空的。 我已附上崩溃日志。我认为除了发生在演员阵容发生的那一行之外,它并没有说太多。这个 fetch 在任何情况下都不应该返回 nil,所以我不知道发生了什么。 【参考方案1】:对象不存在,因此崩溃。就我个人而言,我讨厌快速强制施法。 optionals 的全部意义在于帮助您在某些东西为零时进行管理。将as!
放入您的代码中会要求程序崩溃。我建议删除它并用if let
替换它。如果您 100% 确定它永远不会为零,那么您仍然应该使用 if let
并在 else 报告中报告它发生的崩溃服务(使用 Crashlytics
recordError
- 它会与您的崩溃一起出现) .
至于你的说法:
我确定实体存在,因为我在创建用户时创建了它
坦率地说——你错了。计算机永远是对的,而人类永远是错的。
以下是可能的原因:
将其保存到核心数据时出错我怀疑像大多数程序一样,当您将对象保存到核心数据时您没有检查错误 - 或者如果您确实不知道该怎么做与错误。如果你很聪明,你会记录下来的。最常见的错误是硬盘空间不足。如果对象一开始没有保存,那么当您获取它时它就不会存在。 对象存在但已被删除。如果您的代码中有任何地方删除了此对象,请考虑在此代码运行之前它已被删除的可能性。寻找多线程和竞争条件。 对象尚未保存。如果您的应用中有任何多线程,则应考虑存在竞争条件的可能性。任何这些情况都会导致 0-3% 范围内的崩溃。
【讨论】:
我会将此答案标记为正确,即使我仍然不确定它为什么会发生。我正在做的是保存在后台上下文中,然后将该上下文合并到主上下文中。合并发生在主上下文的 performAndWait 块中,提取也发生在类似的块中。我相信保存到 CoreData 时出错,很遗憾我无法复制它。以上是关于使用 CoreData 获取时崩溃的主要内容,如果未能解决你的问题,请参考以下文章
从 CoreData 实体中的 NSNumber 获取 intValue 时无法识别的选择器崩溃