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?

Sahil Kapoor
la source

Réponses:

379

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

let array = Array(results) // la fin
Mazyod
la source
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).

segiddins
la source
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
}
Sahil Kapoor
la source
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.

NeverwinterMoon
la source
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 }
    }
}
abdullahselek
la source
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
}
Jaseem Abbas
la source
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})
Nosov Pavel
la source
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 .

nRewik
la source
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
Lindaaak
la source
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)
Vinayak
la source
2
extension Results {
    func materialize() -> [Element] {
        return Array(self)
    }
}
Desmond Hume
la source