RealmSwift: Konvertieren Sie Ergebnisse in Swift Array

143

Was ich implementieren möchte:

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

    return objects.count > 0 ? objects : nil
}

Wie kann ich ein Objekt zurückgeben, als [SomeObject]ob Results?

Sahil Kapoor
quelle

Antworten:

379

Seltsam, die Antwort ist sehr einfach. So mache ich das:

let array = Array(results) // la fin
Mazyod
quelle
Gibt es kein NSArray zurück?
Thesummersign
2
@thesummersign Realm hat sich in letzter Zeit stark verändert, aber eines ist sicher: Der obige Code gibt einen Swift zurück, Arrayder mit dem Ergebnisiterator erstellt wurde.
Mazyod
4
Es gibt keine Variablen der Entität zurück (initial)
Nik Kov
2
Ich stimme @NikKov zu, es scheint, dass keine Variablen der Entität zurückgegeben werden (
Jon
2
@ Jon Wie siehst du, dass sie gleich Null sind? Es scheint, als wären sie faul, wenn Sie sie an einem Debug-Punkt angehalten betrachten, erscheinen sie leer, aber wenn Sie sie ausdrucken, greift sie auf sie zu und zeigt den richtigen Wert (für mich) an.
Jeremiah
31

Wenn Sie unbedingt Ihre konvertieren ResultszuArray denken , dass es einen Leistungs- und Speicheraufwand gibt, da dieser Resultsfaul ist. Sie können dies jedoch in einer Zeile tun, wie results.map { $0 }in Swift 2.0 (oder map(results) { $0 }in 1.2).

Segiddins
quelle
Welche Version von Realm?
Sahil Kapoor
31
Ist diese Konvertierung nicht eine Notwendigkeit, wenn Sie die Abhängigkeit von Realm nicht auf zu viele Klassen in Ihrem Projekt übertragen möchten?
Marcin Kuptel
15
map { $0 }wird LazyMapRandomAccessCollectionin Swift 3 zurückkehren, daher ist die @ Mazyod-Antwort besser.
Legoless
@MarcinKuptel ja das ist genau das problem das ich gefunden habe. Ich konnte das Realm-Modell abstrahieren, indem ich eine Struktur erstellte, die einem Protokoll entspricht. Diese Protokollabstraktion definiere ich in meinen Signaturen in meiner Codebasis. Manchmal muss ich jedoch in ein Array konvertieren. Gibt es eine Möglichkeit, eine verzögerte Sammlung meines abstrahierten Protokolls zu erstellen, sodass es nur zur Zugriffszeit in die Struktur konvertiert wird?
Pavan
20

Ich habe eine Lösung gefunden. Erweiterung für Ergebnisse erstellt.

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

und mit like

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

    return objects.count > 0 ? objects : nil
}
Sahil Kapoor
quelle
4
for var i = 0; i < count; i++ sollte ersetzt werden durchfor i in 0 ..< count
Sal
1
Das obige ist eine sehr verwirrende Art, die Erweiterung zu schreiben: Erweiterung Ergebnisse {var array: [Element] {return self.map {$ 0}}}
Giles
10

Mit Swift 4.2 ist es so einfach wie eine Erweiterung:

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

Alle benötigten Generika-Informationen sind bereits ein Teil, Resultsden wir erweitern.

NeverwinterMoon
quelle
8

Dies ist eine weitere Möglichkeit, Resultsin Array mit einer Erweiterung mit Swift 3 in einer einzelnen Zeile zu konvertieren .

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

Für Swift 4 und Xcode 9.2

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

Mit Xcode 10 flatMap veraltet ist , können Sie verwenden compactMapfür die Zuordnung.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
quelle
Da ich diesen Code in der 9.2-Version von XCode verwende, zeigt er mir die Verwendung des nicht deklarierten Typs 'T'
Bhavesh Dhaduk
Meine Antwort wurde aktualisiert. Sie können sie überprüfen.
Abdullahselek
Für Xcode 10 und höher können Sie compactMap anstelle von flatMap verwenden, um die Warnung zu vermeiden.
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
    }
}

Verwendung

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: Generika verwenden

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
quelle
4

Es ist keine gute Idee, Ergebnisse in Array zu konvertieren, da Ergebnisse faul sind. Aber wenn Sie es brauchen, versuchen Sie Folgendes:

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

Besser ist es jedoch, die Ergebnisse überall dort weiterzugeben, wo Sie sie benötigen. Sie können Ergebnisse auch in Liste anstelle von Array konvertieren.

List(realm.objects(class))

Wenn die erste Funktion nicht funktioniert, können Sie diese ausprobieren:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Nosov Pavel
quelle
Nach dem Update von RealmSwift auf 3.4.0 akzeptiert List keine Argumente. Wie konvertiere ich in diesem Fall ein Array in List? Irgendeine Idee?
Nishu_Priya
1
@NishuPriya hier sind Sie myList = List <Person> () myList.append (ObjekteIn: Realm.Objects (Person.self))
Nosov Pavel
2

Ich bin mir nicht sicher, ob es dafür einen effizienten Weg gibt.

Sie können dies jedoch tun, indem Sie ein Swift-Array erstellen und es in die Schleife einfügen.

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

Wenn Sie das Gefühl haben, dass es zu langsam ist. Ich empfehle Ihnen, das Realm- ResultsObjekt direkt weiterzugeben .

nRewik
quelle
Ich habe so etwas nur gemacht, indem ich stattdessen eine Erweiterung für Resules erstellt habe. Ich habe den Code als Antwort gepostet. Danke :)
Sahil Kapoor
Ja. Das würde ich auch tun.
nRewik
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Sie können also Folgendes verwenden:

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

Lösung für Swift 4, Realm 3

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

Jetzt kann die Konvertierung wie folgt durchgeführt werden

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