Realm Swift 后台搜索
Realm Swift background search
我的应用程序中有一个领域数据库,其中包含约 2000 个用户的列表。
一个表格视图显示这些用户,一个搜索栏允许过滤他们(每个用户的 6 个不同属性)。
这个操作阻塞了 UI,所以我把它放在后台线程中。
现在好多了,但我不能 100% 确定这是最好的方法。
如果您有更好的解决方案,能否提出其他解决方案?
这是我使用的示例代码:
func filterUsers(searchText:String,completion: (result: Array<User>) -> ()){
var IIDS = Array<String>()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let predicate1 = NSPredicate(format: "firstName contains[c] %@", searchText)
let predicate2 = NSPredicate(format: "lastName contains[c] %@", searchText)
let bgRealm = try! Realm()
bgRealm.beginWrite()
//Filter the whole list of users
var results = Array(bgRealm.objects(User)).filter {
//One user object by one
let usr:User = [=11=]
//Reset the value by default
usr.searchResultField = ""
if predicate1.evaluateWithObject(usr) {
usr.searchResultField = "firstNameORlastName"
return true
}
else if predicate2.evaluateWithObject(usr) {
usr.searchResultField = "IID"
}
return false
};
try! bgRealm.commitWrite()
for usr in results {
IIDS.append("'\(usr.IID)'")
}
results.removeAll()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let realm = try! Realm()
let foundUsers = Array(realm.objects(User).filter("IID IN {\(IIDS.joinWithSeparator(","))}"))
IIDS.removeAll()
completion(result: foundUsers)
})
})
}
将对象全部拉入内存后过滤对象(通过将 Results
转换为 Array
)。如果让 Realm 处理过滤,您将获得更好的性能。为此,您需要能够通过谓词进行所有查询,您可以将这些谓词组合成一个 OR 复合谓词。
此外,我会避免将匹配字段存储在对象中以分离关注点,因为值是瞬态的。只有当这些对象保存在内存中时才需要它们。
除此之外,我建议为 IID
使用主键,然后通过一个对象检索另一个对象,而不是构建一个包含所有 ID 的巨大谓词。
总而言之,这就是我处理该问题的方式:
func filterUsers(searchText:String, completion: (result: Array<(user: User, field: String)>) -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
var predicates = [
"firstName": NSPredicate(format: "firstName contains[c] %@", searchText)
"lastName": NSPredicate(format: "lastName contains[c] %@", searchText)
]
let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: Array(predicates.values))
let bgRealm = try! Realm()
// Filter the whole list of users
let results = bgRealm.objects(User).filter(compoundPredicate)
// Find out which field is matching
let idsAndFields: [(IID: String, field: String)] = results.flatMap {
for (field, predicate) in predicates {
if predicate.evaluateWithObject([=10=]) {
return (IID: [=10=].IID, field: field)
}
}
return nil
}
dispatch_async(dispatch_get_main_queue()) {
let realm = try! Realm()
let result = idsAndFields.flatMap {
if let user = realm.objectForPrimaryKey([=10=].IID) {
return (user: user, field: [=10=].field)
} else {
return nil
}
}
completion(result: result)
})
}
}
我的应用程序中有一个领域数据库,其中包含约 2000 个用户的列表。
一个表格视图显示这些用户,一个搜索栏允许过滤他们(每个用户的 6 个不同属性)。 这个操作阻塞了 UI,所以我把它放在后台线程中。
现在好多了,但我不能 100% 确定这是最好的方法。
如果您有更好的解决方案,能否提出其他解决方案?
这是我使用的示例代码:
func filterUsers(searchText:String,completion: (result: Array<User>) -> ()){
var IIDS = Array<String>()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
let predicate1 = NSPredicate(format: "firstName contains[c] %@", searchText)
let predicate2 = NSPredicate(format: "lastName contains[c] %@", searchText)
let bgRealm = try! Realm()
bgRealm.beginWrite()
//Filter the whole list of users
var results = Array(bgRealm.objects(User)).filter {
//One user object by one
let usr:User = [=11=]
//Reset the value by default
usr.searchResultField = ""
if predicate1.evaluateWithObject(usr) {
usr.searchResultField = "firstNameORlastName"
return true
}
else if predicate2.evaluateWithObject(usr) {
usr.searchResultField = "IID"
}
return false
};
try! bgRealm.commitWrite()
for usr in results {
IIDS.append("'\(usr.IID)'")
}
results.removeAll()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let realm = try! Realm()
let foundUsers = Array(realm.objects(User).filter("IID IN {\(IIDS.joinWithSeparator(","))}"))
IIDS.removeAll()
completion(result: foundUsers)
})
})
}
将对象全部拉入内存后过滤对象(通过将 Results
转换为 Array
)。如果让 Realm 处理过滤,您将获得更好的性能。为此,您需要能够通过谓词进行所有查询,您可以将这些谓词组合成一个 OR 复合谓词。
此外,我会避免将匹配字段存储在对象中以分离关注点,因为值是瞬态的。只有当这些对象保存在内存中时才需要它们。
除此之外,我建议为 IID
使用主键,然后通过一个对象检索另一个对象,而不是构建一个包含所有 ID 的巨大谓词。
总而言之,这就是我处理该问题的方式:
func filterUsers(searchText:String, completion: (result: Array<(user: User, field: String)>) -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
var predicates = [
"firstName": NSPredicate(format: "firstName contains[c] %@", searchText)
"lastName": NSPredicate(format: "lastName contains[c] %@", searchText)
]
let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: Array(predicates.values))
let bgRealm = try! Realm()
// Filter the whole list of users
let results = bgRealm.objects(User).filter(compoundPredicate)
// Find out which field is matching
let idsAndFields: [(IID: String, field: String)] = results.flatMap {
for (field, predicate) in predicates {
if predicate.evaluateWithObject([=10=]) {
return (IID: [=10=].IID, field: field)
}
}
return nil
}
dispatch_async(dispatch_get_main_queue()) {
let realm = try! Realm()
let result = idsAndFields.flatMap {
if let user = realm.objectForPrimaryKey([=10=].IID) {
return (user: user, field: [=10=].field)
} else {
return nil
}
}
completion(result: result)
})
}
}