使用 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 '((_) -> _)'
。当我使类 Equatable 时,它说这是一种冗余的一致性。
如果您的.text
属性是字符串,则不需要使用equateable,因为字符串是可等价的。尝试铸造。我会更新我的答案。
试过了,返回表达式的类型是不明确的,没有更多的上下文,还有一个错误说Value of type 'Publication' has no member 'text'
,这确实是正确的,因为它可以在[getType]数组下找到,而不是发布对象本身。
请注意,基于闭包的过滤有许多缺点,如这个答案所示:性能和内存开销会更差,当领域发生变化时,生成的集合不会自动更新,并且您无权访问通知等功能。以上是关于使用 Swift 过滤 Realm 对象的主要内容,如果未能解决你的问题,请参考以下文章