【发布时间】:2019-01-18 11:32:21
【问题描述】:
我有一个已发布的应用程序在执行核心数据提取时偶尔会崩溃。我知道崩溃发生在哪里,但我不知道为什么会发生。
应用程序使用了一个选项卡视图控制器,并且崩溃发生在一个以 tableView 作为初始视图的选项卡中。因为每当数据在应用程序的其他地方发生更改时,我都需要更新这个 tableView,所以我在 viewWillAppear 方法中执行获取。
以下是相关代码:
lazy var fetchedResultsController: NSFetchedResultsController<Day> = {
let request: NSFetchRequest<Day> = Day.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
request.predicate = NSPredicate(format: "calories > %@", "0")
let frc = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
return frc
}()
override func viewWillAppear(_ animated: Bool) {
do {
try fetchedResultsController.performFetch()
} catch {
print("Could not fetch results")
}
tableView.reloadData()
}
这是调用堆栈的图像。
我无法在我的设备或模拟器上重现崩溃,所以我真的不知道如何修复这个错误。如有任何解决此问题的建议,我将不胜感激。
这是核心数据模型中calories 属性的屏幕截图。
这是创建Day 实体的类方法。
class func dayWithInfo(date: Date, inManagedContext context: NSManagedObjectContext) -> Day {
let defaults = UserDefaults.standard
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: date)
let request: NSFetchRequest<Day> = Day.fetchRequest()
request.predicate = NSPredicate(format: "dateString = %@", dateString)
if let day = (try? context.fetch(request))?.first {
if let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date()) {
// Update the macro goals if the date is the current or future date
if date > yesterday {
day.proteinGoal = defaults.double(forKey: Constants.UserDefaultKeys.proteinValueKey)
day.carbohydrateGoal = defaults.double(forKey: Constants.UserDefaultKeys.carbohydratesValueKey)
day.lipidGoal = defaults.double(forKey: Constants.UserDefaultKeys.lipidsValueKey)
day.fiberGoal = defaults.double(forKey: Constants.UserDefaultKeys.fiberValueKey)
day.calorieGoal = defaults.double(forKey: Constants.UserDefaultKeys.caloriesValueKey)
}
}
return day
} else {
let day = Day(context: context)
// Set the date as a string representation of a day
day.dateString = dateString
day.date = date
// Set the calorie and macronutrient goals from user defaults
day.proteinGoal = defaults.double(forKey: Constants.UserDefaultKeys.proteinValueKey)
day.carbohydrateGoal = defaults.double(forKey: Constants.UserDefaultKeys.carbohydratesValueKey)
day.lipidGoal = defaults.double(forKey: Constants.UserDefaultKeys.lipidsValueKey)
day.fiberGoal = defaults.double(forKey: Constants.UserDefaultKeys.fiberValueKey)
day.calorieGoal = defaults.double(forKey: Constants.UserDefaultKeys.caloriesValueKey)
// Creat meals and add their ralationship to the day
if let meals = defaults.array(forKey: Constants.UserDefaultKeys.meals) as? [String] {
for (index, name) in meals.enumerated() {
_ = Meal.mealWithInfo(name: name, day: day, slot: index, inManagedContext: context)
}
}
return day
}
}
【问题讨论】:
-
您的
calories列是否可以为空?当您尝试比较未实现选择器的对象时,您的比较谓词似乎失败了。 -
卡路里属性被赋予一个默认值,所以它不应该是零,但你是对的,问题似乎与比较谓词有关。
-
calories属性的类型是什么? -
不确定这与您的崩溃有多相关,但从
viewWillAppear的文档中,“如果您覆盖此方法,您必须在实现中的某个时刻调用 super。”我> -
谓词说明符:developer.apple.com/library/archive/documentation/Cocoa/…。本质上,您正在创建一个字符串,然后通过调用 descriptionWithLocale: 或 description: 在谓词中替换该字符串。虽然 应该 有效,但我想知道是否存在一些边缘情况。既然你知道你的属性是双精度的,你可以使用
NSPredicate(format: "calories > %f", 0.0),但它实际上只是增加了解析开销。我不是 Swift 人,但我认为NSPredicate(format: "calories > 0")应该可以。
标签: ios iphone swift core-data crash-reports