如何为可以 return nil 的 NSPredicate 创建惰性变量

How do I create a lazy var for an NSPredicate that can return nil

我有一个UITableView可以过滤和排序。当用户选择一个过滤器选项时,我试图使用一个名为 liftUuidPredicatelazy var 来构造谓词。用户的选择存储在 UserDefaults 中,但如果没有选择过滤器,UserDefaults.logFilterLiftUuid() 中将没有任何值,这会导致我的应用程序崩溃并出现错误:

NSInvalidArgumentException', reason: '*** -copyWithZone: cannot be sent to an abstract object of class NSPredicate: Create a concrete instance!

显然我需要创建一个 NSPredicate 的具体实例,但是我不知道在没有谓词的情况下该怎么做。

// throws the 'Create a concrete instance' error
lazy var liftUuidPredicate: NSPredicate = {
    guard let liftUuid = UserDefaults.logFilterLiftUuid() else { return NSPredicate() }

    return NSPredicate(format: "uuid = %@", liftUuid)
}()

// fetchedResultsController
func fetchLiftEvents() -> NSFetchedResultsController<NSFetchRequestResult> {
  let moc = stack.managedObjectContext
  let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LiftEvent")

  fetchRequest.predicate = liftUuidPredicate
  if let sortBy = UserDefaults.logSortSelection() {fetchRequest.sortDescriptors = [NSSortDescriptor(key: sortBy, ascending: false)]}

  fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)

  do {
       try fetchedResultsController!.performFetch()
      } catch {
       fatalError("Unable to fetch Lift Events: \(error)")
    }
  return fetchedResultsController!
}

NSPredicate() 的可用方法需要一种格式和某种形式的参数,当我不希望有谓词时,它们将不起作用。在 guard let 语句中,我也尝试了 return NSPredicate(value: false) 但是,正如我所料,fetchRequest 然后没有返回任何记录。

我怎样才能完成这项工作?

NSPredicate 是一个摘要 class。您不能拥有 NSPredicate(),您必须使用所需信息对其进行实例化以获得具体实例。

关键是将 liftUuidPredicate 的类型从 NSPredicate 更改为 NSPredicate? 而不是 returning NSPredicate() return nil 如果 guard 失败。

我添加了一些样板代码来编译我的代码片段,因此您需要根据需要更改它。

`extension UserDefaults {

    class func logFilterLiftUuid() -> String? {
        return "bar"
    }

    class func logSortSelection() -> String? {
        return "bar"
    }

}

class Foo {

    let stack = NSFetchedResultsController<NSManagedObject>()
    var fetchedResultsController = NSFetchedResultsController<NSFetchRequestResult>()
    // throws the 'Create a concrete instance' error
    lazy var liftUuidPredicate: NSPredicate? = {
        guard let liftUuid = UserDefaults.logFilterLiftUuid() else { return nil }

        return NSPredicate(format: "uuid = %@", liftUuid)
    }()

    // fetchedResultsController
    func fetchLiftEvents() -> NSFetchedResultsController<NSFetchRequestResult> {
        let moc = stack.managedObjectContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LiftEvent")

        fetchRequest.predicate = liftUuidPredicate
        if let sortBy = UserDefaults.logSortSelection() {fetchRequest.sortDescriptors = [NSSortDescriptor(key: sortBy, ascending: false)]}

        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)

        do {
            try fetchedResultsController.performFetch()
        } catch {
            fatalError("Unable to fetch Lift Events: \(error)")
        }
        return fetchedResultsController
    }

}