【问题标题】:FetchedResultsController Using Predicate to Exclude Results Contained in a SetFetchedResultsController 使用谓词排除集合中包含的结果
【发布时间】:2018-07-21 19:36:48
【问题描述】:

我正在尝试过滤我的 FetchedResultsController 中的项目以过滤掉一组特定的项目。这些是引擎,其中有特定的字母名称,后跟数字。名称中可能的字母范围是从“A”到“O”。我希望能够根据其他条件过滤掉名称从“D”到“O”的引擎。

我设置了一个常量“highPowerEngines”,它是一个包含这些字母的集合。由于该名称仅包含一个字母,因此我想排除任何包含 highPowerEngines 中任何字母的名称。到目前为止,这是我的代码,我正在处理的谓词包含在 FIXME 之后:

func configureFetchedResultsController() {
    let context = databaseController.getContext()
    let enginesFetchRequest = NSFetchRequest<Engine>(entityName: CoreData.engine)
    let highPowerEngines: Set =  ["D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"]

    var predicate = NSPredicate()
    if currentStage == 1 && stages! == 1 {
        predicate = NSPredicate(format: "engineType == %@", EngineType.singleStage.rawValue)
    } else if currentStage < stages! {
        predicate = NSPredicate(format: "engineType == %@", EngineType.boosterStage.rawValue)
    } else {
        predicate = NSPredicate(format: "engineType == %@", EngineType.upperStage.rawValue)
    }

    var predicateArray:[NSPredicate] = [
        predicate
        ]
    // FIXME: Sort out highPowerEngines
    if !dPlusEngineIAP {
        if currentStage == 1 && stages! == 1 {
            predicate = NSPredicate(format: "NOT engineDesignation CONTAINS %@", highPowerEngines)
            predicateArray.append(predicate)
        }
    }

    let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
    enginesFetchRequest.predicate = compoundPredicate

    let primarySortDescriptor = NSSortDescriptor(key: CoreData.isMadeByName, ascending: true)
    let secondarySortDescriptor = NSSortDescriptor(key: CoreData.engineDesignation, ascending: true)
    enginesFetchRequest.sortDescriptors = [primarySortDescriptor, secondarySortDescriptor]


    self.fetchedResultsController = NSFetchedResultsController<Engine>(
        fetchRequest: enginesFetchRequest,
        managedObjectContext: context,
        sectionNameKeyPath: CoreData.isMadeByName,
        cacheName: nil)

    self.fetchedResultsController.delegate = self

}

【问题讨论】:

    标签: swift core-data swift4


    【解决方案1】:

    使用 IN 而不是 CONTAINS

    NOT (engineDesignation IN %@)
    

    更新

    既然您想排除除树字母之外的所有字母,为什么不将谓词转为包含而不是排除,例如

    engineDesignation BEGINSWITH ‘A’ OR
    engineDesignation BEGINSWITH ‘B’ OR
    engineDesignation BEGINSWITH ‘C’
    

    【讨论】:

    • 不排除大功率发动机。我放了一个断点,它肯定是在执行代码。有什么想法吗?
    • 另外,engineDesignation 是一个字符串,它是一个字母后跟其他非字母字符,如果这会改变的话。
    • 如果它以字母开头,您应该使用 BEGINSWITH 但我很确定这不适用于 Set 并且我真的没有看到任何解决方案,那么它可以与集合一起使用除了创建一个庞大的复合 OR 谓词并分别检查每个字母之外的字母。
    • @Yrb 我用替代解决方案更新了我的答案
    • 不高兴。它无法用“或”解析它。你是对的,BEGINSWITH 不适用于集合或数组。我能告诉你我真的很讨厌谓词中的字符串文字吗?!?
    【解决方案2】:

    感谢这里的帖子:CoreData Predicate get every sentence that contains any word in array ,我终于能够解决我的问题。我当前的工作代码在这里:

    func configureFetchedResultsController() {
        let context = databaseController.getContext()
        let enginesFetchRequest = NSFetchRequest<Engine>(entityName: CoreData.engine)
        let lowPowerEngines =  ["A", "B", "C"]
    
        var predicate = NSPredicate()
        if currentStage == 1 && stages! == 1 {
            predicate = NSPredicate(format: "engineType == %@", EngineType.singleStage.rawValue)
        } else if currentStage < stages! {
            predicate = NSPredicate(format: "engineType == %@", EngineType.boosterStage.rawValue)
        } else {
            predicate = NSPredicate(format: "engineType == %@", EngineType.upperStage.rawValue)
        }
    
        var predicateArray:[NSPredicate] = [
            predicate
            ]
    
        if !dPlusEngineIAP {
            let predicates = lowPowerEngines.map {
                NSPredicate(format: "engineDesignation CONTAINS %@", $0)
            }
            let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
                predicateArray.append(predicate)
        }
    
        let compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
        enginesFetchRequest.predicate = compoundPredicate
    
        let primarySortDescriptor = NSSortDescriptor(key: CoreData.isMadeByName, ascending: true)
        let secondarySortDescriptor = NSSortDescriptor(key: CoreData.engineDesignation, ascending: true)
        enginesFetchRequest.sortDescriptors = [primarySortDescriptor, secondarySortDescriptor]
    
    
        self.fetchedResultsController = NSFetchedResultsController<Engine>(
            fetchRequest: enginesFetchRequest,
            managedObjectContext: context,
            sectionNameKeyPath: CoreData.isMadeByName,
            cacheName: nil)
    
        self.fetchedResultsController.delegate = self
    
    }
    

    处理数组中每个项目的解决方案是使用 map 函数创建一个复合谓词。然后将复合谓词添加到 fetchedResultsController。这让我可以比较引擎,看看它是否在 lowPowerEngines 中。 Map 为 lowPowerEngines 中的每个项目创建一个单独的谓词。我什至可以即时以编程方式更改它。我真的希望这对某人有所帮助,因为没有中心位置可以提出这些技巧。当我收集到足够的它们时,我会做一个主帖。

    【讨论】:

      猜你喜欢
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多