RealmSwift: конвертировать результаты в массив Swift

143

Что я хочу реализовать:

class func getSomeObject() -> [SomeObject]? {
    let objects = Realm().objects(SomeObject)

    return objects.count > 0 ? objects : nil
}

Как я могу вернуть объект, как [SomeObject]если бы Results?

Сахил Капур
источник

Ответы:

379

Странно, ответ очень прямой. Вот как я это делаю:

let array = Array(results) // la fin
Mazyod
источник
не возвращает NSArray?
thesummersign
2
В последнее время @thesummersign Realm сильно изменилась, но одно можно сказать наверняка: приведенный выше код возвращает Swift, Arrayсозданный с помощью итератора результатов.
Mazyod
4
Возвращает ноль переменных сущности (начальная)
Ник Ков
2
Я согласен с @NikKov, похоже, он возвращает ноль переменных сущности; (
Jon
2
@Jon Как ты видишь, что они ноль? Кажется, что поскольку они ленивые, когда вы смотрите на них, остановленные в точке отладки, они кажутся пустыми, но если вы распечатываете их, они получают к ним доступ и показывают правильное значение (для меня).
Иеремия
31

Если вам абсолютно необходимо преобразовать его Resultsв Array, имейте в виду, что это Resultsсвязано с производительностью и объемом памяти, так как это лениво. Но вы можете сделать это в одну строку, как results.map { $0 }в Swift 2.0 (или map(results) { $0 }в 1.2).

segiddins
источник
Какая версия Realm?
Сахил Капур
31
Не является ли это преобразование необходимостью, если вы не хотите передавать зависимость от Realm слишком многим классам в вашем проекте?
Марцин Куптел
15
map { $0 }вернется LazyMapRandomAccessCollectionв Swift 3, так что ответ @Mazyod лучше.
Legoless
@MarcinKuptel да, это именно та проблема, которую я нашел. Я смог абстрагировать модель области, создав структуру, соответствующую протоколу, и именно эту абстракцию протокола я определяю в своих сигнатурах в своей кодовой базе. Однако иногда мне нужно преобразовать в массив, есть ли способ, которым я могу иметь ленивую коллекцию моего абстрактного протокола, чтобы он преобразовывался только в структуру во время доступа?
Паван
20

Я нашел решение. Создано расширение по результатам.

extension Results {
    func toArray<T>(ofType: T.Type) -> [T] {
        var array = [T]()
        for i in 0 ..< count {
            if let result = self[i] as? T {
                array.append(result)
            }
        }

        return array
    }
}

и используя как

class func getSomeObject() -> [SomeObject]? {
    let objects = Realm().objects(SomeObject).toArray(SomeObject) as [SomeObject]

    return objects.count > 0 ? objects : nil
}
Сахил Капур
источник
4
for var i = 0; i < count; i++ следует заменить наfor i in 0 ..< count
Sal
1
Вышеприведённый способ написания расширения очень запутан: расширение Results {var array: [Element] {return self.map {$ 0}}}
Giles
10

С Swift 4.2 это так же просто, как расширение:

extension Results {
    func toArray() -> [Element] {
      return compactMap {
        $0
      }
    }
 }

Вся необходимая общая информация уже является частью, Resultsкоторую мы расширяем.

NeverwinterMoon
источник
8

Это еще один способ преобразования Resultsв массив с расширением Swift 3 в одну строку.

extension Results {
    func toArray() -> [T] {
        return self.map { $0 }
    }
}

Для Swift 4 и Xcode 9.2

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return flatMap { $0 as? T }
    }
}

С Xcode 10 flatMap устарела, вы можете использовать compactMapдля отображения.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
источник
Поскольку я использую этот код в версии 9.2 XCode, он показывает мне использование необъявленного типа 'T'
Бхавеш Дхадук
Обновил мой ответ, вы можете проверить его.
abdullahselek
Для Xcode 10 и выше вы можете использовать compactMap вместо flatMap, чтобы избежать предупреждения.
Методий Здравкин
6

Swift 3

extension Results {
    func toArray<T>(ofType: T.Type) -> [T] {
        var array = [T]()
        for i in 0 ..< count {
            if let result = self[i] as? T {
                array.append(result)
            }
        }

        return array
    }
}

использование

class func getSomeObject() -> [SomeObject]? {
   let defaultRealm = try! Realm()
    let objects = defaultRealm.objects(SomeObject.self).toArray(ofType : SomeObject.self) as [SomeObject]

    return objects.count > 0 ? objects : nil
}

Альтернатива: использование дженериков

class func getSomeObject() -> [T]? {
        let objects = Realm().objects(T.self as! Object.Type).toArray(ofType : T.self) as [T]

        return objects.count > 0 ? objects : nil
}
Джасим Аббас
источник
4

не очень хорошая идея конвертировать результаты в массив, потому что результаты ленивы. Но если вам нужно попробовать это:

func toArray<T>(ofType: T.Type) -> [T] {
    return flatMap { $0 as? T }
}

но лучший способ - передавать результаты везде, где вам нужно. Также вы можете конвертировать результаты в список вместо массива.

List(realm.objects(class))

если первая функция не работает, вы можете попробовать это:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Носов Павел
источник
После обновления RealmSwift до 3.4.0, List не принимает аргументы. Как преобразовать массив в список в этом случае? Любая идея?
Nishu_Priya
1
@NishuPriya здесь вы можете позволить myList = List <Person> () myList.append (objectsIn: realm.objects (Person.self))
Носов Павел
2

Я не уверен, есть ли эффективный способ сделать это.

Но вы можете сделать это, создав массив Swift и добавив его в цикл.

class func getSomeObject() -> [SomeObject]? {
    var someObjects: [SomeObject] = []
    let objects = Realm().objects(SomeObject)
    for object in objects{
        someObjects += [object]
    }
    return objects.count > 0 ? someObjects : nil
}

Если вы чувствуете, что это слишком медленно. Я рекомендую вам обойти Resultsобъект Realm напрямую.

nRewik
источник
Я сделал что-то подобное, только создав вместо этого расширение в Resules. Я отправил код как ответ. Спасибо :)
Сахил Капур
Да. Я бы тоже так сделал.
nRewik
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Итак, вы можете использовать как:

Realm().objects(SomeClass.self).filter("someKey ENDSWITH %@", "sth").array
lindaaak
источник
2

Решение для Swift 4, Realm 3

extension Results {
    func toArray<T>(ofType: T.Type) -> [T] {
        let array = Array(self) as! [T]
        return array
    }
}

Теперь преобразование может быть сделано, как показано ниже

let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)
Винаяк
источник
2
extension Results {
    func materialize() -> [Element] {
        return Array(self)
    }
}
Десмонд Хьюм
источник