RealmSwift: 将 Results 转换为 Swift 数组

177

我想要实现的是:

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

    return objects.count > 0 ? objects : nil
}

我怎样才能返回对象作为[SomeObject]而不是Results

12个回答

443

奇怪,答案非常简单。这是我做的方法:

let array = Array(results) // la fin

它不是返回一个NSArray吗? - geekay
2
@thesummersign 最近 Realm 已经发生了很多变化,但有一件事是肯定的:以上代码返回用结果迭代器构造的 Swift Array - Mazyod
4
返回实体的空变量(初始状态)。 - Nike Kov
2
我同意 @NikKov 的观点,它似乎返回实体的 nil 变量 ;( - Jon
3
@Jon 你是如何看出它们是空的?因为它们是惰性加载,当你在调试点停止时,它们似乎是空的,但如果你将它们打印出来,它会访问并显示正确的值(对我来说是这样)。 - Jeremiah

34
如果您确实必须将Results转换为Array,请记住它会有性能和内存开销,因为Results是惰性加载的。但是在一行中可以这样做:results.map { $0 } 在Swift 2.0中(或者在1.2中使用map(results) { $0 })。

Realm的哪个版本? - Sahil Kapoor
37
如果您不希望在项目中泄露太多对Realm的依赖关系,那么这种转换难道不是必要的吗? - Marcin Kuptel
15
在Swift 3中,map { $0 }将返回LazyMapRandomAccessCollection,因此@Mazyod的答案更好。 - Legoless
@MarcinKuptel 是的,那正是我发现的问题。我已经通过创建符合协议的结构体来抽象出领域模型,并且在我的代码库中定义了这个协议抽象。然而有时我需要转换为数组,有没有办法可以拥有一个懒加载的抽象协议集合,以便它只在访问时转换为结构体? - Pavan

23
我找到了一个解决方案。在结果中创建了一个扩展。
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
    }
}

并且使用类似的
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++ should be replaced with for i in 0 ..< count - Sal
1
以上是一种非常令人困惑的编写扩展的方式:extension Results { var array: [Element] { return self.map { $0 } } } - Giles

21

使用Swift 4.2只需要一个扩展即可:

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

所有必要的泛型信息已经包含在我们扩展的Results中。

要使用它:

let someModelResults: Results<SomeModel> = realm.objects(SomeModel.self)
let someModelArray: [SomeModel] = someModelResults.toArray()

你如何使用那个函数? - Yash Jain
1
realm.objects(SomeModel.self).toArray() - NeverwinterMoon

9

这是使用Swift 3中的扩展将Results转换为数组的另一种方法,可以在一行中完成。

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

针对 Swift 4 和 Xcode 9.2

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

Xcode 10中,flatMap已被弃用,您可以使用compactMap进行映射。

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

由于我正在使用XCode 9.2版本,它显示了“使用未声明的类型'T'”错误。 - Bhavesh Dhaduk
我更新了我的回答,你可以查看一下。 - abdullahselek
对于 Xcode 10 及以上版本,您可以使用 compactMap 替代 flatMap 来避免警告。 - Metodij Zdravkin
你好!请问如何调用toArray函数?我需要将Results<Int>转换为[Int]。 - Abrcd18

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

用法

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
}

替代方案:使用泛型

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

将Results转换为数组不是一个好主意,因为Results是惰性的。但如果您需要尝试这样做:

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

但更好的方法是在需要时传递结果。您还可以将结果转换为列表而不是数组。

List(realm.objects(class))

如果第一个函数不起作用,您可以尝试这个函数:
var refrenceBook:[RefrenceProtocol] = []
let faceTypes = Array(realm.objects(FaceType))
refrenceBook = faceTypes.map({$0 as FaceType})

更新RealmSwift到3.4.0版本后,List不再接受参数。在这种情况下如何将数组转换为List?有什么想法吗? - Nishu_Priya
2
@NishuPriya 在这里,你看看这段代码: let myList = List<Person>() myList.append(objectsIn: realm.objects(Person.self)) - Nosov Pavel

3

针对 Swift 4,Realm 3 的解决方案

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

现在可以按以下方式进行转换。
let array = Realm().objects(SomeClass).toArray(ofType: SomeClass.self)

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

所以,您可以像这样使用:

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

2

我不确定是否有任何高效的方法来做到这一点。

但是你可以通过创建一个Swift数组并在循环中添加它来实现。

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

如果你感觉速度太慢,我建议你直接传递 Realm Results 对象。

我是通过在Resules上创建扩展来实现类似的功能。我已将代码发布为答案。谢谢 :) - Sahil Kapoor
是的,我也会这样做。 - nRewik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接