【问题标题】:NSPredicate with condition based on recursive relationship - Swift - Core DataNSPredicate 与基于递归关系的条件 - Swift - Core Data
【发布时间】:2019-02-05 22:54:21
【问题描述】:

我正在使用 Core Data,并且我有一个基本的文件夹结构。每个项目(文件/文件夹)是表中的一行。每个项目都有一个name 属性和一个可选的关系,它指向作为其父项的项目。我正在尝试编写一个函数,该函数接受表示路径的字符串数组(例如["myFolder", "mySubfolder", "mySubSubfolder", "myFile"])并返回在该路径中找到的项目。用英文,我想问Core Data是“给我所有名称为myFile,其父母姓名为mySubSubfolder,其祖父母姓名为mySubfolder,其曾祖父母姓名为myFolder的项目” .用文字描述这一点更简单的方法是定义一个名为item(at: path) 的条件,它对Core Data 说“给我所有名称为path.last 并且其父项满足item(at: path.dropLast()) 的项目”。我心里希望谓词有一个奇特的功能可以使这成为可能,但是我对他们来说足够新,以至于我无法通过谷歌搜索找到答案。

【问题讨论】:

    标签: swift recursion core-data nspredicate recursive-query


    【解决方案1】:

    我喜欢尽可能使用强类型方法,而不是在运行时构造和解析格式字符串。

    import Foundation
    
    func predicateMatchingPath(_ path: [String]) -> NSPredicate {
        var path = path
        guard let last = path.popLast() else {
            return NSPredicate(value: false)
        }
    
        var ancestorKeyPath = ""
        let nameSuffix = "name"
        var predicates = [NSPredicate]()
    
        predicates.append(NSComparisonPredicate(
            leftExpression: NSExpression(forKeyPath: ancestorKeyPath + nameSuffix),
            rightExpression: NSExpression(forConstantValue: last),
            modifier: .direct, type: .equalTo, options: []))
    
        while let anscestor = path.popLast() {
            ancestorKeyPath.append("parent.")
            predicates.append(NSComparisonPredicate(
                leftExpression: NSExpression(forKeyPath: ancestorKeyPath + nameSuffix),
                rightExpression: NSExpression(forConstantValue: anscestor),
                modifier: .direct, type: .equalTo, options: []))
        }
    
        // Make sure the most distant ancestor is a root.
        predicates.append(NSComparisonPredicate(
            leftExpression: NSExpression(forKeyPath: ancestorKeyPath + "parent"),
            rightExpression: NSExpression(forConstantValue: nil),
            modifier: .direct, type: .equalTo, options: []))
    
        return NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
    }
    
    print(predicateMatchingPath(["myFolder", "mySubfolder", "mySubSubfolder", "myFile"]))
    
    // Output:
    name == "myFile" AND parent.name == "mySubSubfolder" AND parent.parent.name == "mySubfolder" AND parent.parent.parent.name == "myFolder" AND parent.parent.parent.parent == nil
    

    【讨论】:

    • 我了解使用类型系统的好处,但在这种情况下,大量的额外代码似乎不值得。您的方法是否有实实在在的好处?
    【解决方案2】:

    好吧,其实我想我明白了。尚未对其进行实际测试,但从概念上讲它似乎是正确的。这是创建正确谓词字符串的代码:

    var predicateString = ""
    var i = 0
    for pathComponent in path.reversed() {
        predicateString += "name == \(pathComponent) && parent"
        for _ in 0 ..< i {
            predicateString += ".parent"
        }
        i += 1
        guard i != path.count else { continue }
        predicateString += "."
    }
    predicateString += " == nil"
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-15
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 2016-08-31
      • 2021-05-03
      • 1970-01-01
      相关资源
      最近更新 更多