RealmSwift: Konwertuj wyniki na Swift Array

143

Co chcę wdrożyć:

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

    return objects.count > 0 ? objects : nil
}

Jak mogę zwrócić obiekt, jakby [SomeObject]zamiast tego Results?

Sahil Kapoor
źródło

Odpowiedzi:

379

Dziwne, odpowiedź jest bardzo prosta. Oto jak to robię:

let array = Array(results) // la fin
Mazyod
źródło
czy nie zwraca NSArray?
thesummersign
2
@thesummersign Realm ostatnio bardzo się zmieniło, ale jedno jest pewne: powyższy kod zwraca Swift Arrayskonstruowany z iteratorem wyników.
Mozyod
4
Zwraca zero vars jednostki (początkowe)
Nik Kov
2
Zgadzam się z @NikKov, wygląda na to, że zwraca zero wartości jednostki; (
Jon
2
@Jon Jak widzisz, że są zerowe? Wygląda na to, że ponieważ są leniwe, kiedy patrzysz na nie zatrzymane w punkcie debugowania, wydają się puste, ale jeśli je wydrukujesz, uzyskuje do nich dostęp i pokazuje poprawną wartość (dla mnie).
Jeremiah
31

Jeśli absolutnie musisz przekonwertować swój program Resultsna Array, pamiętaj, że istnieje narzut wydajności i pamięci, ponieważ Resultsjest leniwy. Ale możesz to zrobić w jednej linii, jak results.map { $0 }w swift 2.0 (lub map(results) { $0 }w 1.2).

segiddins
źródło
Która wersja Realm?
Sahil Kapoor
31
Czy ta konwersja nie jest koniecznością, jeśli nie chcesz przeciekać zależności od Realm do zbyt wielu klas w swoim projekcie?
Marcin Kuptel
15
map { $0 }powróci LazyMapRandomAccessCollectionw Swift 3, więc odpowiedź @Mazyod jest lepsza.
Bezprawny
@MarcinKuptel tak, to jest dokładnie ten problem, który znalazłem. Udało mi się wyodrębnić model dziedziny, tworząc strukturę zgodną z protokołem i to właśnie ta abstrakcja protokołu jest definiowana w moich podpisach w mojej bazie kodu. Jednak czasami muszę przekonwertować na tablicę, czy istnieje sposób, aby mieć leniwą kolekcję mojego wyabstrahowanego protokołu, tak aby konwertował on do struktury tylko w czasie dostępu?
Pavan,
20

Znalazłem rozwiązanie. Utworzono rozszerzenie w wynikach.

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

i używając like

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

    return objects.count > 0 ? objects : nil
}
Sahil Kapoor
źródło
4
for var i = 0; i < count; i++ należy zastąpićfor i in 0 ..< count
Sal
1
Powyższy sposób pisania rozszerzenia jest bardzo mylący: rozszerzenie Wyniki {var array: [Element] {return self.map {$ 0}}}
Giles
10

Dzięki Swift 4.2 jest to tak proste, jak rozszerzenie:

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

Wszystkie potrzebne informacje ogólne są już częścią, Resultsktórą rozszerzamy.

NeverwinterMoon
źródło
8

To kolejny sposób na konwersję Resultsdo Array z rozszerzeniem z Swift 3 w jednej linii.

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

Dla Swift 4 i Xcode 9.2

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

Z Xcode 10 flatMap jest przestarzały, możesz go używać compactMapdo mapowania.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
źródło
Ponieważ używam tego kodu w wersji 9.2 XCode, pokazuje mi użycie niezadeklarowanego typu
``
Zaktualizowałem moją odpowiedź, możesz to sprawdzić.
abdullahselek,
W przypadku Xcode 10 i nowszych możesz użyć compactMap zamiast flatMap, aby uniknąć ostrzeżenia.
Metodij Zdravkin
6

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

Stosowanie

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
}

Alternatywa: używanie typów ogólnych

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
źródło
4

nie jest dobrym pomysłem konwertowanie wyników na tablicę, ponieważ wyniki są leniwe. Ale jeśli potrzebujesz, spróbuj tego:

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

ale lepszym sposobem jest przekazywanie wyników w dowolnym miejscu. Możesz także przekonwertować wyniki na listę zamiast na tablicę.

List(realm.objects(class))

jeśli pierwsza funkcja nie działa, możesz wypróbować tę:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Nosov Pavel
źródło
Po zaktualizowaniu RealmSwift do 3.4.0, List nie przyjmuje argumentów. Jak w takim przypadku przekonwertować tablicę na List? Dowolny pomysł?
Nishu_Priya
1
@NishuPriya, masz pozwolenie myList = List <Person> () myList.append (objectsIn: realm.objects (Person.self))
Nosov Pavel
2

Nie jestem pewien, czy istnieje jakiś skuteczny sposób, aby to zrobić.

Ale możesz to zrobić, tworząc tablicę Swift i dołączając ją w pętli.

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

Jeśli uważasz, że jest za wolno. Polecam ci Resultsbezpośrednio ominąć obiekt Realm .

nRewik
źródło
Zrobiłem coś takiego tylko tworząc rozszerzenie w Resules. Wysłałem kod jako odpowiedź. Dzięki :)
Sahil Kapoor
Tak. Ja też bym to zrobił.
nRewik
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

Możesz więc użyć:

Realm().objects(SomeClass.self).filter("someKey ENDSWITH %@", "sth").array
lindaaak
źródło
2

Rozwiązanie dla Swift 4, Realm 3

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

Teraz konwersję można wykonać jak poniżej

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