使用 Swift 过滤 Realm 对象

Posted

技术标签:

【中文标题】使用 Swift 过滤 Realm 对象【英文标题】:Filtering Realm objects with Swift 【发布时间】: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 = ""

【问题讨论】:

你的Publication对象实现是什么? 可以在这里找到:***.com/questions/36835805/… 【参考方案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]数组下找到,而不是发布对象本身。 请注意,基于闭包的过滤有许多缺点,如这个答案所示:性能和内存开销会更差,当领域发生变化时,生成的集合不会自动更新,并且您无权访问通知等功能。

以上是关于使用 Swift 过滤 Realm 对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Realm swift 中过滤为当前日期创建的事件?

如何通过 NSDate 属性过滤 Realm 对象

iOS Realm过滤关系列表中的对象

从 Realm 数据库中检索单个对象的正确方法

在Realm过滤父母和子女 - Android

解释这段代码:使用字符串作为过滤函数