RealmSwift: Converter resultados em matriz rápida

143

O que eu quero implementar:

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

    return objects.count > 0 ? objects : nil
}

Como posso retornar um objeto como [SomeObject]se Results?

Sahil Kapoor
fonte

Respostas:

379

Estranho, a resposta é muito direta. Aqui está como eu faço isso:

let array = Array(results) // la fin
Mazyod
fonte
não retorna um NSArray?
Thesummersign
2
@thesummersign O domínio está mudando muito recentemente, mas uma coisa é certa: o código acima retorna um Swift Arrayconstruído com o iterador de resultados.
Mazyod 13/11/2015
4
Ele retornar vars nil da entidade (inicial)
Nik Kov
2
Eu concordo com @NikKov, parece estar retornando nulos vars da entidade; (
Jon
2
@ Jon Como você está vendo que eles são nulos? Parece que, como eles são preguiçosos, quando você os vê parados em um ponto de depuração, eles parecem vazios, mas se você os imprime, os acessa e mostra o valor correto (para mim).
Jeremiah
31

Se você absolutamente precisa converter o seu Resultspara Array, lembre-se de que há uma sobrecarga de desempenho e memória, pois Resultsé preguiçoso. Mas você pode fazer isso em uma linha, como results.map { $0 }no swift 2.0 (ou map(results) { $0 }no 1.2).

segiddins
fonte
Qual versão do Reino?
Sahil Kapoor
31
Essa conversão não é necessária se você não deseja vazar a dependência do Realm para muitas classes no seu projeto?
Marcin Kuptel 10/10/2015
15
map { $0 }retornará LazyMapRandomAccessCollectionno Swift 3, então a resposta do @Mazyod é melhor.
Legoless 14/09/16
@ MarcinKuptel sim, esse é exatamente o problema que encontrei. Consegui abstrair o modelo de região criando uma estrutura que se adapta a um protocolo, e é essa abstração de protocolo que eu defino nas minhas assinaturas na minha base de código. No entanto, às vezes eu preciso converter para uma matriz, existe uma maneira de ter uma coleção lenta do meu protocolo abstraído para que ele apenas seja convertido na estrutura no momento do acesso?
Pavan
20

Eu encontrei uma solução. Extensão criada em 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
    }
}

e usando como

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

    return objects.count > 0 ? objects : nil
}
Sahil Kapoor
fonte
4
for var i = 0; i < count; i++ deve ser substituído porfor i in 0 ..< count
Sal
1
A descrição acima é uma maneira muito confusa de escrever a extensão: extension Results {array de variedades: [Element] {return self.map {$ 0}}}
Giles
10

Com o Swift 4.2, é tão simples quanto uma extensão:

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

Todas as informações genéricas necessárias já fazem parte das Resultsquais estendemos.

NeverwinterMoon
fonte
8

Essa é outra maneira de converter Resultsem Array com uma extensão com o Swift 3 em uma única linha.

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

Para Swift 4 e Xcode 9.2

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

Com o Xcode 10 flatMap está obsoleto, você pode usar compactMappara mapear.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
fonte
Como eu estou usando esse código em 9,2 versão do Xcode, ele me mostra Uso de tipo não declarado 'T'
Bhavesh Dhaduk
Atualizado minha resposta, você pode conferir.
abdullahselek
Para o Xcode 10 e superior, você pode usar o compactMap em vez do flatMap para evitar o aviso.
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: Usando 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
fonte
4

não é uma boa ideia converter Resultados em Matriz, porque Resultados é preguiçoso. Mas se você precisar, tente o seguinte:

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

mas a melhor maneira é passar os Resultados sempre que precisar. Além disso, você pode converter Resultados em Lista em vez de Matriz.

List(realm.objects(class))

se a primeira função não estiver funcionando, você pode tentar esta:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Nosov Pavel
fonte
Depois de atualizar o RealmSwift para 3.4.0, a Lista não aceita argumentos. Como converter uma matriz para List neste caso? Qualquer ideia?
Nishu_Priya
1
@NishuPriya aqui está você deixe myList = List <Person> () minhalista.append (objectsIn: realm.objects (Person.self))
Nosov Pavel
2

Não tenho certeza, se existe alguma maneira eficiente de fazer isso.

Mas você pode fazer isso criando uma matriz Swift e anexando-a no loop.

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

Se você sentir que é muito lento. Eu recomendo que você passe Resultsdiretamente o objeto Realm .

nRewik
fonte
Fiz algo assim apenas criando uma extensão no Resules. Publiquei o código como resposta. Obrigado :)
Sahil Kapoor
sim. Eu faria isso também.
NRewik
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Então, você pode usar como:

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

Solução para Swift 4, Domínio 3

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

Agora a conversão pode ser feita como abaixo

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