【问题标题】:Filtering Realm objects with Swift使用 Swift 过滤 Realm 对象
【发布时间】:2016-04-25 14:28:13
【问题描述】:

在尝试使用NSPredicate 过滤我的 Realm 数据库时,我总是收到以下错误:

属性“文本”不是“getType”类型对象中的链接

我想过滤我的 Realm 数据库以仅显示其中包含某些特定文本的项目。这是我尝试过的:

let realm = try! Realm()
let predicate = NSPredicate(format: "typez.text.filter = 'special'")
let filterThis = realm.objects(Publication).filter(predicate)
print(filterThis)

我的模型类的相关部分是:

class Publication: Object, Mappable {
    dynamic var id: Int = 0
    var typez = List<getType>()
    dynamic var url: String?
}

class getType: Object, Mappable {
    dynamic var text: String = ""
}

【问题讨论】:

标签: swift nspredicate realm


【解决方案1】:

您提到模型类的相关部分如下所示:

class Publication: Object, Mappable {
    dynamic var id: Int = 0
    var typez = List<getType>()
    dynamic var url: String?
}

class getType: Object, Mappable {
    dynamic var text: String = ""
}

如果我对您的理解正确,您希望在其typez 列表中找到text 等于special 的条目的Publication 实例。你可以这样表达:

let realm = try! Realm()
let result = realm.objects(Publication).filter("ANY typez.text = 'special'")
print(result)

【讨论】:

  • 之前试过了,但是报错Key paths that include an array property must use aggregate operations'
  • 我的错误。您需要包含像 ANY 这样的修饰符来指定 List 中必须匹配多少元素才能将包含对象视为匹配。我已经更新了答案。
【解决方案2】:

我不喜欢这里接受的答案,因为它实际上并没有回答问题......但它对我的帮助比我意识到的要大。我现在将尽可能使用闭包而不是 NSPredicates。这个问题的实际答案应该是@NSGangster 答案的略微修改版本:

let realm = try! Realm()
    //Array of publications             
    let realmObjects = realm.objects(Publication)
    //any publication where .text property == special will be filtered. and filter out empty array
    let filterThis = realmObjects.filter({ $0.typez.filter({ $0.text == "special" } != [] ) })
    print(filterThis)

.. 或类似的东西。

但我所寻找的有点不同。我需要一种方法来过滤多词字符串的确切词,并且使用带有“CONTAINS”的 NSPredicate 将匹配任何包含子字符串,例如搜索“red”将匹配“fred”。 Realm 还不支持“LIKE”或正则表达式,所以我只能使用闭包:

//I was going for a "related terms" result for a dictionary app
let theResults = terms.filter(
    {
        //Looking for other terms in my collection that contained the
        //title of the current term in their definition or more_info strings
        $0.definition.components(separatedBy: " ").contains(term.title) ||
        $0.more_info.components(separatedBy: " ").contains(term.title)
    }
)

我花了一天的时间进行搜索,希望这可以帮助遇到类似问题的其他人。

【讨论】:

  • Realm 从早期的 v2.1.2 开始支持 LIKE。还请注意,像您展示的那样基于闭包进行过滤有许多缺点:性能和内存开销会更差,当领域更改时,结果集合不会自动更新,并且您无权访问功能比如通知。
【解决方案3】:

我通常不直接使用 NSPredicate,而是在过滤器参数中进行内联谓词闭包。

let realm = try! Realm()
                     //Array of publications             
    let realmObjects = realm.objects(Publication)
    //any publication where .text property == special will be filtered. and filter out empty array
    let filterThis = realmObjects.filter({ $0.getType.filter({ $0.text == "special" } != [] ) })
    print(filterThis)

【讨论】:

  • 我推荐这个 article 来学习更多关于新的 swift 数组方法的酷技巧,包括如何使用 $0.property 闭包语法和 filter/map/reduce
  • 给我以下错误:Cannot invoke 'filter' with an argument list of type '((_) -&gt; _)'。当我使类 Equatable 时,它​​说这是一种冗余的一致性。
  • 如果您的.text 属性是字符串,则不需要使用equateable,因为字符串是可等价的。尝试铸造。我会更新我的答案。
  • 试过了,返回表达式的类型是不明确的,没有更多的上下文,还有一个错误说Value of type 'Publication' has no member 'text',这确实是正确的,因为它可以在[getType]数组下找到,而不是发布对象本身。
  • 请注意,基于闭包的过滤有许多缺点,如这个答案所示:性能和内存开销会更差,当领域发生变化时,生成的集合不会自动更新,并且您无权访问通知等功能。
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 2018-09-09
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多