【问题标题】:FetchedResultsController with transient attribute for comparing dates具有用于比较日期的瞬态属性的 FetchedResultsController
【发布时间】:2019-01-20 03:09:02
【问题描述】:

我在 CoreData 中有一个 JOURNEY 实体。它具有到达日期和离开日期作为属性。

arrivalDate 和 leaveDate 都是 NSDate 类型?

我只想获取那些持续时间超过一个小时的旅程。

为了实现这一点,我在 Journey+CoreDataClass 中创建了一个瞬态属性

public var isJourneyLongEnough: Bool{
    if let arrival = arrivalDate as Date?, let departure = departureDate as Date?{
        let duration = departure.timeIntervalSince(arrival)
        return duration >= 3600 ? true : false
    } else{
        return false
    }
}

当我尝试获取它时崩溃并出现错误:*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:在实体中找不到“keypath isJourneyLongEnough”。

在研究有关此问题的更多信息时,我发现我们不能在谓词中使用瞬态属性,因为在从 persistentStore 获取托管对象时这些属性不存在。

您不能使用基于瞬态属性的谓词进行获取(尽管您可以使用瞬态属性自己在内存中进行过滤)。 ...总而言之,如果您直接执行 fetch,则通常不应将基于 Objective-C 的谓词或排序描述符添加到 fetch 请求中。相反,您应该将这些应用于获取的结果。

实现这一目标的最佳方法是什么?我正在使用 FetchedResultsController 在 UITableView 中显示所有旅程

【问题讨论】:

    标签: ios swift core-data nsfetchedresultscontroller


    【解决方案1】:

    您可以尝试以下 NSPredicate,它基于 another question,本质上将日期转换为 NSNumber,减去它们,然后比较结果是否大于或小于 3600 秒。

    我没试过,但也许有帮助。最初的问题是在 ObjC 中,所以也许有些事情发生了变化。

    NSPredicate(format: “departureDate != nil AND arrivalDate != nil AND CAST(departureDate, ‘NSNumber‘) - CAST(arrivalDate, ‘NSNumber‘) >= 3600“)
    

    【讨论】:

    • 我也试过这种方式,但它给了我错误。 CoreData:错误:异常处理请求:,不支持的函数表达式 CAST(departureDate, "NSNumber") - CAST(arrivalDate, "NSNUmber") with userInfo of (null)
    • arrivalDate 和 leaveDate 在 JOURNEY 实体中是可选的。 let predicate = NSPredicate(格式: "arrivalDate != nil AND leaveDate != nil AND (CAST(departureDate, 'NSNumber') - CAST(arrivalDate, 'NSNUmber')) >= 3600")
    • 这是我在崩溃时遇到的错误*** 由于未捕获的异常 'NSInvalidArgumentException' 导致应用程序终止,原因:'不支持的函数表达式 CAST(departureDate, "NSNumber") - CAST(arrivalDate, "NSNumber")'
    • 也许到达日期或离开日期为零?在这种情况下,您可以将其过滤掉,我为此编辑了答案。您也可以在 CoreData 中将它们设为必需,以便在保存时崩溃,以防它们未设置。
    【解决方案2】:

    时间戳存储为秒(自参考日期 2001 年 1 月 1 日起) 在 Core Data SQLite 文件中,可以简单地检查两者之间的区别 出发和到达日期至少为 3600 秒:

    let predicate = NSPredicate(format: "arrivalDate - departureDate >= 3600")
    fetchRequest.predicate = predicate
    

    这在我的测试中按预期工作。如果最短行程时间 在运行时确定,使用

    let minDuration = 3600
    let predicate = NSPredicate(format: "arrivalDate - departureDate >= %@", minDuration as NSNumber)
    

    备注: 上述谓词仅在 Core Data 中使用时才有效 获取请求。以下变体适用于 Core Data 获取请求并使用直接评估的谓词:

     NSPredicate(format: "arrivalDate.timeIntervalSinceReferenceDate - departureDate.timeIntervalSinceReferenceDate >= 3600")
    

    【讨论】:

    • 我已经尝试过你的方法来减去它在获取结果时工作的日期。一天后,当新对象添加到数据库时,应用程序开始崩溃。 *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“数学函数需要 NSNumber 参数”我猜我需要将其转换为 NSNumber
    • @FE_Tech:您是否尝试过其他方法(使用 timeIntervalSinceReferenceDate)?
    • 是的,使用 timeIntervalSinceReferenceDate 方法,我的旅程都没有获取。我没有从数据库中获取任何对象。而我的 TableView 是空的。
    • @FE_Tech:它在我的测试中有效,但我稍后会仔细检查。否则我目前没有更好的主意,抱歉。
    • 使用 timeIntervalSinceReferenceDate 是有效的。这个问题对我来说是另一回事。我不知道为什么添加新对象时第一种方法会导致崩溃。但是这个 timeIntervalSinceReferenceDate 即使在添加新对象时也能正常工作。
    猜你喜欢
    • 2013-12-07
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 2014-06-25
    • 2021-08-05
    • 1970-01-01
    相关资源
    最近更新 更多