代码之家  ›  专栏  ›  技术社区  ›  andrewbuilder

将嵌套的条件If语句转换为复杂的NSCompoundPredicate

  •  0
  • andrewbuilder  · 技术社区  · 4 年前

    我正在使用SwiftUI为一个旧的基于iOS的项目编写macOS目标。Is是一个核心数据驱动的应用程序,对于macOS目标,我已经成功地使用动态@FetchRequest实现了通用列表,主要如Paul Hudson在他的 blog .

    我主要是通过遵循苹果的 SwiftUI Tutorials 并复制所提供的示例代码。

    之前使用的条件if语句主动过滤了每个SwiftUI List 基于3个UI控件。

    Image of three UI controls to "filter" the SwiftUI List

    // PART 1
        if (!self.appData.showFavouritesOnly
            || fetchedEvent.isFavourite)
    // PART 2
        && (self.searchText.count == 0
            || (fetchedEvent.eventName?.contains(self.searchText) == true))
    // PART 3
        && (self.filter == .all
            || self.filter.name == fetchedEvent.eventCategory
            || (self.filter.category == .featured && fetchedEvent.isFeatured)) {
    

    现在我有了一个使用谓词的通用@FetchRequest,我想将这个条件if语句翻译成 NSCompoundPredicate .

    我将包括整个初始化器,这样你就可以看到动态@FetchRequest是如何构建的,但我需要帮助的是谓词。。。

    init(sortDescriptors: [NSSortDescriptor],
         searchKey: String,
         searchValue: String?,
         showFavourites: Bool,
         filterKey: String,
         filter: FilterType,
         @ViewBuilder content: @escaping (T) -> Content) {
    
        let entity = T.entity
        let predicateTrue = NSPredicate(value: true)
    // PART 1
        let predicateFavourite = showFavourites == false ? predicateTrue : NSPredicate(format: "isFavourite == TRUE")
    // PART 2
        let predicateSearch = searchValue?.count == 0 ? predicateTrue : NSPredicate(format: "%K CONTAINS[cd] %@", searchKey, searchValue!)
    
        // The initialiser works perfectly down to this point...then...
    // PART 3
        let predicateFilterName = filter == .all ? predicateTrue : NSPredicate(format: "%K == %@", filterKey, filter.name as CVarArg)
        let predicateFilterFeature = filter.category == .featured ? NSPredicate(format: "isFeatured == TRUE") : predicateTrue
    
        let predicateOr = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateFilterName, predicateFilterFeature])
        let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateFavourite, predicateSearch, predicateOr])
    
        fetchRequest =
            FetchRequest<T>(entity: entity,
                            sortDescriptors: sortDescriptors,
                            predicate: predicate)
    
        self.content = content
    }
    

    第3部分中包含的代码部分有效。切换 FilterType.all FilterType.featured 进行了预期的更改,但我很难为选择另一个类别的“其他”情况编写谓词——也就是说——不是特色,而是两者兼而有之 .lakes , .rivers .mountains .

    为了完整起见,我还包括了枚举 Category 和结构 FilterType ...

    enum Category: String, CaseIterable, Codable, Hashable {
    
        case featured = "Featured"
        case lakes = "Lakes"
        case rivers = "Rivers"
        case mountains = "Mountains"
    }
    
    struct FilterType: CaseIterable, Hashable, Identifiable {
    
        var name: String
        var category: Category?
    
        init(_ category: Category) {
            self.name = category.rawValue
            self.category = category
        }
    
        init(name: String) {
            self.name = name
            self.category = nil
        }
    
        static var all = FilterType(name: "All")
    
        static var allCases: [FilterType] {
            return [.all] + Category.allCases.map(FilterType.init)
        }
    
        var id: FilterType {
            return self
        }
    
    }
    
    0 回复  |  直到 4 年前
        1
  •  1
  •   pbasdf    4 年前

    我认为问题就在这里:

     let predicateFilterFeature = filter.category == .featured ? NSPredicate(format: "isFeatured == TRUE") : predicateTrue
    

    如果过滤器是 .lakes 等等,则此子副本将为TRUE,当与 predicateFilterName 覆盖它。尝试返回FALSE:

     let predicateFilterFeature = filter.category == .featured ? NSPredicate(format: "isFeatured == TRUE") : predicateFalse
    
        2
  •  0
  •   andrewbuilder    4 年前

    我的答案是一个欺诈性的答案,因为这是我在尝试以不同的方式思考谓词的构造后偶然发现的一个黑客解决方案。(它没有表现出对理解我写的谓词语法的实际问题的任何仔细思考!)

    因此,这个回复没有回答我最初的问题——@pbasdf已经回答了这个问题——尽管这个回复达到了同样的结果。

    那么,也许还有另一种解决方案?!?

    let predicateTrue = NSPredicate(value: true)
    
    let predicateFavourite = showFavourites == false ? predicateTrue : NSPredicate(format: "isFavourite == TRUE")
    
    let predicateSearch = searchValue?.count == 0 ? predicateTrue : NSPredicate(format: "%K CONTAINS[cd] %@", searchKey, searchValue!)
    
    let predicateFilterFeatured = NSPredicate(format: "isFeatured == TRUE")
    let predicateFilterName = NSPredicate(format: "%K == %@", filterKey, filter.name as CVarArg)
    let predicateFilterCategory = filter.category == .featured ? predicateFilterFeatured : predicateFilterName
    
    let predicateFilter = filter == .all ? predicateTrue : predicateFilterCategory
    
    let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateFavourite, predicateSearch, predicateFilter])
    
    推荐文章