2016-04-06 9 views
2

У меня есть база данных realm в моем приложении, содержащая список из ~ 2000 пользователей.Realm Swift background search

В таблице отображаются эти пользователи, а панель поиска позволяет фильтровать их (по 6 различным свойствам каждого пользователя). Эта операция блокировала пользовательский интерфейс, поэтому я помещал его в фоновый поток.

Теперь это намного лучше, но я не уверен на 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 = $0 
      //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) 
     }) 
    }) 
} 

ответ

2

Вы отфильтрованы те объекты, заваливая их всех в памяти (путем преобразования Results к Array). У вас будет гораздо более высокая производительность, если вы разрешите Realm обрабатывать фильтрацию. Для этого вам нужно будет сделать все ваши запросы по предикатам, которые вы можете комбинировать с одним предикатом OR-соединения.

Кроме того, я бы избежал хранения соответствующего поля в объекте, чтобы разделить проблемы, поскольку значения являются временными. Они нужны только до тех пор, пока эти объекты хранятся в памяти.

Кроме того, я бы рекомендовал использовать первичный ключ для IID, а затем просто получить один объект другим, а не создавать огромный предикат со всеми идентификаторами.

Чтобы поставить все это вместе, это было бы так, как я бы решить, что:

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($0) { 
        return (IID: $0.IID, field: field) 
       } 
      } 
      return nil 
     } 

     dispatch_async(dispatch_get_main_queue()) { 
      let realm = try! Realm() 
      let result = idsAndFields.flatMap { 
       if let user = realm.objectForPrimaryKey($0.IID) { 
        return (user: user, field: $0.field) 
       } else { 
        return nil 
       } 
      } 
      completion(result: result) 
     }) 
    } 
}