176

What I want to implement:

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

    return objects.count > 0 ? objects : nil
}

How can I return object as [SomeObject] instead if Results?

Sahil Kapoor
  • 11,183
  • 13
  • 64
  • 87

12 Answers12

442

Weird, the answer is very straightforward. Here is how I do it:

let array = Array(results) // la fin
aheze
  • 24,434
  • 8
  • 68
  • 125
Mazyod
  • 22,319
  • 10
  • 92
  • 157
  • doesn't it returns an NSArray? – geekay Nov 13 '15 at 18:59
  • 2
    @thesummersign Realm has been changing a lot recently, but one thing is for sure: The code above returns a Swift `Array` constructed with the results iterator. – Mazyod Nov 13 '15 at 19:04
  • 4
    It return nil vars of the entity (initial) – Nike Kov Sep 08 '17 at 14:20
  • 2
    I agree with @NikKov, it seems to be returning nil vars of the entity ;( – Jon Feb 10 '18 at 08:40
  • 3
    @Jon How are you seeing that they are nil? It seems like since they are lazy, when you look at them stopped at a debug point they appear empty but if you print them out it accesses them and shows the correct value (for me). – Jeremiah Dec 12 '18 at 15:23
34

If you absolutely must convert your Results to Array, keep in mind there's a performance and memory overhead, since Results is lazy. But you can do it in one line, as results.map { $0 } in swift 2.0 (or map(results) { $0 } in 1.2).

segiddins
  • 4,110
  • 1
  • 17
  • 22
  • Which version of Realm? – Sahil Kapoor Jul 01 '15 at 14:01
  • 37
    Isn't this conversion a necessity if you don't want to leak dependency on Realm to too many classes in your project? – Marcin Kuptel Oct 10 '15 at 14:49
  • 15
    `map { $0 }` will return `LazyMapRandomAccessCollection` in Swift 3, so @Mazyod answer is better. – Legoless Sep 14 '16 at 18:09
  • @MarcinKuptel yes that's exactly the problem I found. I've been able to abstract away the realm model by creating a struct which conforms to a protocol, and it's this protocol abstraction that I define in my signatures in my codebase. However sometimes I need to convert to an array, is there way I can have a lazy collection of my abstracted protocol so that it only converts to the struct at access time? – Pavan Sep 11 '18 at 11:52
23

I found a solution. Created extension on Results.

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

and using like

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

    return objects.count > 0 ? objects : nil
}
Sahil Kapoor
  • 11,183
  • 13
  • 64
  • 87
  • 4
    `for var i = 0; i < count; i++ ` should be replaced with `for i in 0 ..< count ` – Sal Jun 05 '16 at 15:21
  • 1
    The above is very confusing way of writing the extension: extension Results { var array: [Element] { return self.map { $0 } } } – Giles Aug 14 '18 at 10:06
21

With Swift 4.2 it's as simple as an extension:

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

All the needed generics information is already a part of Results which we extend.

To use this:

let someModelResults: Results<SomeModel> = realm.objects(SomeModel.self)
let someModelArray: [SomeModel] = someModelResults.toArray()
NeverwinterMoon
  • 2,363
  • 21
  • 24
9

This an another way of converting Results into Array with an extension with Swift 3 in a single line.

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

For Swift 4 and Xcode 9.2

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

With Xcode 10 flatMap is deprecated you can use compactMap for mapping.

extension Results {
    func toArray<T>(type: T.Type) -> [T] {
        return compactMap { $0 as? T }
    }
}
abdullahselek
  • 7,893
  • 3
  • 50
  • 40
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 : Using generics

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
}
Muhammad Noman
  • 1,566
  • 1
  • 15
  • 21
Jaseem Abbas
  • 5,028
  • 6
  • 48
  • 73
4

it's not a good idea to convert Results to Array, because Results is lazy. But if you need try this:

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

but better way is to pass Results wherever you need. Also you can convert Results to List instead of Array.

List(realm.objects(class))

if the first func is not working you can try this one:

var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})
Nosov Pavel
  • 1,571
  • 1
  • 18
  • 34
3

Solution for Swift 4, Realm 3

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

Now converting can be done as below

let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)
Vinayak
  • 523
  • 1
  • 9
  • 20
2

I'm not sure, if there is any efficient way to do this.

But you can do it by create a Swift array and append it in the 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
}

If you feel it's too slow. I recommend you to pass around Realm Results object directly.

nRewik
  • 8,958
  • 4
  • 23
  • 30
2
extension Results {
    var array: [Element]? {
        return self.count > 0 ? self.map { $0 } : nil
    }
}

So, you can use like:

Realm().objects(SomeClass.self).filter("someKey ENDSWITH %@", "sth").array
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
lindaaak
  • 21
  • 2
2
extension Results {
    func materialize() -> [Element] {
        return Array(self)
    }
}
Desmond Hume
  • 8,037
  • 14
  • 65
  • 112
0

Using Swift 5 and RealmSwift v10.20.0

This methods works:

private func convertToArray<R>(results: Results<R>) -> [R] where R: Object {
    var arrayOfResults: [R] = []
    for result in results {
        arrayOfResults.append(result)
    }
    return arrayOfResults
}
Miguel Gallego
  • 427
  • 4
  • 7