Фоновый поиск Realm Swift

В моем приложении есть база данных области, содержащая список пользователей ~ 2000.

Табличное представление отображает этих пользователей, а панель поиска позволяет их фильтровать (по 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)
        })
    })
}

person Arnaud    schedule 06.04.2016    source источник


Ответы (1)


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

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

Кроме того, я бы рекомендовал использовать первичный ключ для 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)
        })
    }
}
person marius    schedule 06.04.2016