RealmSwift: Convierta los resultados a Swift Array

143

Lo que quiero implementar:

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

    return objects.count > 0 ? objects : nil
}

¿Cómo puedo devolver un objeto como [SomeObject]si en su lugar Results?

Sahil Kapoor
fuente

Respuestas:

379

Extraño, la respuesta es muy sencilla. Así es como lo hago:

let array = Array(results) // la fin
Mazyod
fuente
¿No devuelve un NSArray?
thesummersign
2
@thesummersign Realm ha cambiado mucho recientemente, pero una cosa es segura: el código anterior devuelve un Swift Arrayconstruido con el iterador de resultados.
Mazyod
44
Devuelve nulo vars de la entidad (inicial)
Nik Kov
2
Estoy de acuerdo con @NikKov, parece estar volviendo nulos en la entidad; (
Jon
2
@ Jon ¿Cómo ves que son nulos? Parece que, dado que son vagos, cuando los mira detenidos en un punto de depuración, aparecen vacíos, pero si los imprime, accede a ellos y muestra el valor correcto (para mí).
Jeremías
31

Si es absolutamente necesario convertir Resultsa Array, tenga en cuenta que hay una sobrecarga de rendimiento y la memoria, ya que Resultses perezoso. Pero puede hacerlo en una línea, como results.map { $0 }en swift 2.0 (o map(results) { $0 }en 1.2).

segiddins
fuente
¿Qué versión de Realm?
Sahil Kapoor
31
¿No es necesaria esta conversión si no quieres filtrar la dependencia de Realm a demasiadas clases en tu proyecto?
Marcin Kuptel
15
map { $0 }regresará LazyMapRandomAccessCollectionen Swift 3, por lo que la respuesta de @Mazyod es mejor.
Legoless
@MarcinKuptel sí, ese es exactamente el problema que encontré. He podido abstraer el modelo de reino creando una estructura que se ajusta a un protocolo, y es esta abstracción de protocolo la que defino en mis firmas en mi base de código. Sin embargo, a veces necesito convertir a una matriz, ¿hay alguna manera de tener una colección diferida de mi protocolo abstraído para que solo se convierta a la estructura en el momento del acceso?
Pavan
20

Encontré una solución. Extensión creada en los resultados.

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
    }
}

y usando como

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

    return objects.count > 0 ? objects : nil
}
Sahil Kapoor
fuente
44
for var i = 0; i < count; i++ debe ser reemplazado confor i in 0 ..< count
Sal
1
Lo anterior es una forma muy confusa de escribir la extensión: extensión Resultados {var array: [Elemento] {return self.map {$ 0}}}
Giles
10

Con Swift 4.2 es tan simple como una extensión:

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

Toda la información genérica necesaria ya es parte de la Resultscual ampliamos.

NeverwinterMoon
fuente
8

Esta es otra forma de convertir Resultsen Array con una extensión con Swift 3 en una sola línea.

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

Para Swift 4 y Xcode 9.2

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

Con Xcode 10 flatMap está en desuso, puede usarlo compactMappara el mapeo.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
fuente
Como estoy usando este código en la versión 9.2 de XCode, me muestra Uso del tipo no declarado 'T'
Bhavesh Dhaduk
Actualicé mi respuesta, puedes verificarlo.
abdullahselek
Para Xcode 10 y superior, puede usar compactMap en lugar de flatMap para evitar la advertencia.
Metodij Zdravkin
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
    }
}

Uso

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
}

Alternativa: uso de genéricos

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
}
Jaseem Abbas
fuente
4

no es una buena idea convertir Results a Array, porque Results es vago. Pero si necesitas probar esto:

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

pero la mejor manera es pasar resultados donde lo necesite. También puede convertir Resultados a Lista en lugar de Array.

List(realm.objects(class))

Si el primer func no funciona, puede probar este:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Nosov Pavel
fuente
Después de actualizar RealmSwift a 3.4.0, List no toma argumentos. ¿Cómo convertir una matriz a List en este caso? ¿Alguna idea?
Nishu_Priya
1
@NishuPriya aquí está permitido myList = List <Person> () myList.append (objectsIn: realm.objects (Person.self))
Nosov Pavel
2

No estoy seguro, si hay alguna manera eficiente de hacer esto.

Pero puede hacerlo creando una matriz Swift y anexándola en el bucle.

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

Si sientes que es demasiado lento. Te recomiendo que pases el Resultsobjeto Realm directamente.

nRewik
fuente
Hice algo así solo creando una extensión en Resules. He publicado el código como respuesta. Gracias :)
Sahil Kapoor
Si. Yo también haría eso.
nRewik
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Entonces, puedes usar como:

Realm().objects(SomeClass.self).filter("someKey ENDSWITH %@", "sth").array
lindaaak
fuente
2

Solución para Swift 4, Reino 3

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

Ahora la conversión se puede hacer de la siguiente manera

let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)
Vinayak
fuente
2
extension Results {
    func materialize() -> [Element] {
        return Array(self)
    }
}
Desmond Hume
fuente