RealmSwift: convertir les résultats en Swift Array


143

Ce que je souhaite mettre en œuvre:

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

    return objects.count > 0 ? objects : nil
}

Comment puis-je retourner un objet comme [SomeObject]si Results?

Réponses:


379

Bizarre, la réponse est très simple. Voici comment je le fais:

let array = Array(results) // la fin

ne renvoie-t-il pas un NSArray?
thesummersign

2
@thesummersign Realm a beaucoup changé récemment, mais une chose est sûre: le code ci-dessus renvoie un Swift Arrayconstruit avec l'itérateur de résultats.
Mazyod

4
Il retourne nil vars de l'entité (initiale)
Nik Kov

2
Je suis d'accord avec @NikKov, il semble ne renvoyer aucun vars de l'entité; (
Jon

2
@Jon Comment voyez-vous qu'ils sont nuls? Il semble que comme ils sont paresseux, lorsque vous les regardez arrêtés à un point de débogage, ils semblent vides, mais si vous les imprimez, il y accède et affiche la valeur correcte (pour moi).
Jeremiah

31

Si vous devez absolument convertir votre Resultsen Array, gardez à l'esprit qu'il y a une surcharge de performances et de mémoire, car Resultsc'est paresseux. Mais vous pouvez le faire en une seule ligne, comme results.map { $0 }dans swift 2.0 (ou map(results) { $0 }en 1.2).


Quelle version de Realm?
Sahil Kapoor

31
Cette conversion n'est-elle pas une nécessité si vous ne voulez pas divulguer la dépendance à Realm vers trop de classes dans votre projet?
Marcin Kuptel

15
map { $0 }reviendra LazyMapRandomAccessCollectiondans Swift 3, donc la réponse @Mazyod est meilleure.
Legoless le

@MarcinKuptel oui c'est exactement le problème que j'ai trouvé. J'ai pu faire abstraction du modèle de domaine en créant une structure conforme à un protocole, et c'est cette abstraction de protocole que je définis dans mes signatures dans ma base de code. Cependant, parfois j'ai besoin de convertir en un tableau, y a-t-il un moyen d'avoir une collection paresseuse de mon protocole abstrait afin qu'il ne se convertisse qu'en struct au moment de l'accès?
Pavan le

20

J'ai trouvé une solution. Extension créée sur les résultats.

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

et en utilisant comme

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++ devrait être remplacé parfor i in 0 ..< count
Sal

1
Ce qui précède est une façon très déroutante d'écrire l'extension: Résultats d'extension {var array: [Element] {return self.map {$ 0}}}
Giles

10

Avec Swift 4.2, c'est aussi simple qu'une extension:

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

Toutes les informations génériques nécessaires font déjà partie de Resultsce que nous étendons.


8

C'est une autre façon de convertir Resultsen Array avec une extension avec Swift 3 en une seule ligne.

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

Pour Swift 4 et Xcode 9.2

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

Avec Xcode 10 flatMap est obsolète, vous pouvez l'utiliser compactMappour le mappage.

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

Comme
j'utilise

Mis à jour ma réponse, vous pouvez la vérifier.
abdullahselek

Pour Xcode 10 et supérieur, vous pouvez utiliser compactMap au lieu de flatMap pour éviter l'avertissement.
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
    }
}

Usage

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
}

Alternative: utiliser des génériques

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

ce n'est pas une bonne idée de convertir Results en Array, car Results est paresseux. Mais si vous avez besoin d'essayer ceci:

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

mais le meilleur moyen est de transmettre les résultats là où vous en avez besoin. Vous pouvez également convertir les résultats en liste au lieu de tableau.

List(realm.objects(class))

si la première fonction ne fonctionne pas, vous pouvez essayer celle-ci:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})

Après la mise à jour de RealmSwift vers 3.4.0, List ne prend pas d'arguments. Comment convertir un tableau en liste dans ce cas? Une idée?
Nishu_Priya

1
@NishuPriya ici, vous êtes laissé myList = List <Person> () myList.append (objectsIn: realm.objects (Person.self))
Nosov Pavel

2

Je ne sais pas s'il existe un moyen efficace de le faire.

Mais vous pouvez le faire en créant un tableau Swift et en l'ajoutant à la boucle.

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 vous pensez que c'est trop lent. Je vous recommande de faire circuler Resultsdirectement l'objet Realm .


J'ai fait quelque chose comme ça uniquement en créant une extension sur Resules à la place. J'ai posté le code comme réponse. Thanks :)
Sahil Kapoor

Ouais. Je ferais ça aussi.
nRewik

2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Donc, vous pouvez utiliser comme:

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

2

Solution pour Swift 4, Realm 3

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

Maintenant, la conversion peut être effectuée comme ci-dessous

let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)

2
extension Results {
    func materialize() -> [Element] {
        return Array(self)
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.