iOS:选择 Realm 而不是 CoreData

作者:Tomasz Szulc,原文链接,原文日期:2015-11-29
译者:Cee;校对:千叶知风;定稿:千叶知风

我已在网上多次看到「Realm」这个词。我甚至曾在十月时有机会参加由 Swift 用户组组织的 Realm 聚会。最终,我有机会用上了 Realm 这个框架。

案例

现在我正在节食。我需要减一些体重因为在加利福尼亚的时候胖了好多 – 好吃的食物实在是太多了:)!我浏览了一下 iTunes Store 中的那些能够追踪喝水记录的应用,但是在我看来这些应用要么看上去很糟糕,要么交互实在是很烂。我想:如果我决定做一个应用,岂不是一箭双雕吗 – 我又能写一个我想要的应用,又能选择使用 Realm 而不是 Core Data。所以我开工了。

你知道当我看完文档、开始使用 Realm 框架的第一感觉是什么吗?哇,这简直真是太棒了!这些开发的家伙做的简直超棒!

免责声明:接下来所写的仅仅只覆盖了 Realm 框架中最基本的一部分。我建议你们接下来可以去阅读官方文档来获取更多的信息。在这儿我并不想向你们展示关于 Realm 框架的全部内容,因为这篇文章不可能像文档一样又臭又长,并且我自己也会避免这样的问题发生。官方的文档非常的棒,你在开工前可以先读一下它。

我的这个案例并不是很复杂而是非常简单的。整个 app 只有两个抽象模型(Model)类: DayDrinkLogEntry 。此外,这个 app 也需要这些功能:添加、更新、筛选和排序存储的数据。正如我所说这是个简单的 app 。接下来我会呈现 app 中的一些代码片段。

抽象模型(Model)

Realm 中没有像 xcdatamodel-like 这样的文件。抽象模型仅仅是继承自 Object 类的文件。

/**
 表示了用户一天的生活。 Day 这个类的信息包含用户所喝的水和他们的每天喝水的目标。
*/
class Day: Object {
    
    dynamic var identifier: String!
    
    /// 表示一天的开始的时间戳(UTC+0 时区)
    dynamic var timestamp: NSTimeInterval = 0
    
    /// 用户所喝的水的量(毫升)
    dynamic var waterDrank: Float = 0
    
    /// 用户每天喝水的目标(毫升)
    dynamic var dailyGoal: Float = 0 // ml
    
    var drinkLogs = List<DrinkLogEntry>()
    
    convenience init(timestamp: NSTimeInterval) {
        self.init()
        self.timestamp = timestamp
        self.identifier = Day.convertTimestampIntoIdentifier(timestamp)
    }
    
    override class func primaryKey() -> String? {
        return "identifier"
    }
    
    override class func indexedProperties() -> [String] {
        return ["identifier"]
    }
    
    class func convertTimestampIntoIdentifier(timestamp: NSTimeInterval) -> String {
        return String(format: "%.0f", arguments: [timestamp])
    }
}

所有前有 dynamic 关键字的属性都会被转化成数据抽象层的一部分。Realm 也支持关系型数据。在这个例子中 Day 这个类中存在 drinkLogs 的一对多关系。一对一的关系就仅是类中的特定属性了。

Realm 也支持从 Core Data 中迁移数据。当你需要迁移的时候,可以定义一个闭包并且执行它,然后你就能顺利地执行迁移属性的所有步骤了(译者注:如何从 Core Data 迁移到 Realm)。

索引属性(Indexed properties)和主键(Primary keys)

Realm 框架有很多 Core Data 中没有的新特性(也有可能是我没找到,或者说我就是想提一下这点😊)。第一点就是「索引属性」了。你可以定义需要被索引的属性集合。当属性个数比较小的时候,搜索会变得很快。这有助于性能的提升。

接下来不得不提一下「主键」。你可以定义抽象模型中的一个属性作为它的主键。这能保证更加有效地更新数据以及保证数据的唯一性。

在我使用的这个例子中,主键和索引属性将作为「标识符」,被用于搜索和更新数据。

数据中也可以有被忽略的属性,那些属性将不被持久化保存。

创建、更新并写入数据

你可以使用未被持久化过的抽象模型,而且这些数据可以被持久化时,你可以将它们写入 Realm 中。比起 Core Data,这就是我为什么喜欢 Realm 更多一点 – 因为它能够很好地解决一些临时数据的问题。

let day = Day(timestamp: timestamp)
day.dailyGoal = MenuSettings().dailyGoal

为了能够写入 Realm 或者从 Realm 中读取,你需要创建 Realm 实例:

let realm = try! Realm()

这是如何将数据添加到数据库的方法:

try! realm.write {
    realm.add(day)
}

我特别喜欢 Realm 中更新数据的方式。我们假设一下有一部分数据是从网络上下载的,并且他们被映射过而且已经加进了数据库。在数据库中已经存在的数据仅需要更新而不是再次添加。

func fetchAll(completion: [Day] -> Void) {
    /**
     假设请求返回了 JSON 并且数据已经映射到了抽象数据层的 Day 类型。
          
     创建的数据还没有存入数据库 Realm 中。
     数据的标识符是相等的时间戳。
     */
    let day1 = Day(timestamp: 0)
    let day2 = Day(timestamp: 86400)
    let day3 = Day(timestamp: 172800)
    
    completion([day1, day2, day3])
}
 
func sync() {
    fetchAll { (days) -> Void in
        let realm = try! Realm()
        try! realm.write {
            /// 如果有相同的标识符,那么它将会被更新。
            realm.add(days, update: true)
        }
    }
}

这是一种比手动查询带有相同标识符然后更新值域更好的方法。

如果更新的参数被置为 false,那么新的数据将具有和在数据库中存在的数据相同的主键。异常会被抛出。

还有其他一些方法来更新数据,在这篇文章中我就不涉及了。

这是如何得到所有 Day 类型数据的方法:

let days = realm.objects(Day.self)

筛选数据也很简单:

realm.objects(Day.self).filter("identifier == %@", dayIdentifier)

按照时间戳升序排列这些数据:

let days = realm.objects(Day.self).sorted("timestamp", ascending: true)

当你每次执行 object()sorted()filter() 后均会得到一个 Results<T> 类型的数据。这能让你对结果进行额外的筛选排序等操作 - 这功能非常的强大而且非常好使。

小结

在下一个有更加复杂的数据模型的 app 中我还会使用 Realm 吗?答案是肯定的。因为整个框架使用起来非常的简单、集成起来非常的快速,而且 Realm 提供了非常多而且强大的功能特性。

P.S. 这个 app 正在等待过审 :)

2015/12/06更新
这个应用上架了 - Water Intake

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容