美文网首页
移动开发数据库篇 之 SwiftRealm(上)

移动开发数据库篇 之 SwiftRealm(上)

作者: JARVIS_STUDIO | 来源:发表于2016-04-05 23:09 被阅读2203次

    移动开发数据库篇 之 SwiftRealm(上)


    @author fharmony Email Weibo or Github


    Realm is a mobile database
    hundreds of millions of people rely on .

    1. 为什么要使用SwiftRealm?

    新型数据库,同类型三方库有CoreDataSQLite
    特点:简单、快、文档规范、免费
    需要:iOS 8.0+(指的是Swift版本)

    需要继承Object,具有一定程度的侵入性。和AVOS Object类似。但是需要注意的是,如果使用的话realm是存储在本地的数据,和AVOS Object存储在云端的数据作用不一样。

    快速集成

    使用Cocoapods快速集成,请参考这个文章
    podfile内容:

    platform :ios,'8.0'
    use_frameworks!
    target '<#你的TargetName#>' do
    pod 'RealmSwift'
    end
    

    2. 数据模型 - 关系

    数据模型的创建

    可以使用Realm提供的Realm Model创建,文件需要满足:

    • 指定数据类型或者是List类型
    • 一定需要初始化

    数据模型的关系

    • 一对一关系 可以为空
    • 一对多关系 通过List完成,提供了List类来作为列表
    • 反向关系 可以通过一个特定的属性获取和给定对象有关系的所有对象。即「具有XX属性的那些对象」

    数据类型:

    常用类型:Bool\Double\Float\String\NSDate\NSData\Int32\Object
    可选与不可选类型

    * 对于基本类型来说:
    let style = RealmOptional<Int32>() --> 可选值
    dynamic var style = 32 --> 不可选值
    
    * 对对象类型来说
    let var value:Stirng? = nil --> 可选值
    dynamic var value = ""
    

    为什么使用dynamic?因为realm工作基于OC运行时。
    为什么不使用计算属性?计算属性将不会被存储到realm里面

    索引属性

    重写Object.indexedProperties()添加索引属性,支持用字符串、整数、布尔值、NSDate作为索引,有利于提高检索效率。

    主键

    重写Object.primaryKey()添加主键,主键不可修改而且能让查询更加高效。注意数据库的主键是条目的唯一标示,如果有两条主键相同的条目,那么后来的条目会更新前一个条目的数据。

    忽略属性

    重写 Object.ignoredProperties() 可以忽略 Realm 存储数据模型的某个属性。

    3.对数据库的操作

    对象存储

    对对象存储的更改需要通过写入事务write闭包完成。
    如果您想要在多个线程中共享对象,或者在应用重启后重复使用对象,那么您必须将其存储到Realm数据库中——这个操作必须在写入事务中完成。
    写入事务可能会失败,所以需要添加throws标记处理异常

    • 增删改
    let realm = try! Realm()//建立realm数据库
    try! realm.write{
        realm.add(object)//插入新对象
        object.name = "new value"//更新数值
        realm.add(object,update:true)//对已经存在的值进行更新操作,或者是对不存在的值进行写入,是否存在依据的是主键
        realm.delete(object)//删除对象
    
    }
    
    * 查  
    
    

    返回Results实例,查询得到的是数据库里面的数据,在写入操作的时候可以修改数据库的数据。您可以将 Results 存储为一个属性,这样就无需在每次访问前都要刷新数据以确保数据最新了。realm的查询允许链式查询。

    let dogs = realm.Objects(Dog)
    let tanDogs = realm.Objects(Dog).filter("NSPredicate断言")
    
    • 排序
      根据某个属性进行排序
    let sortedDogs = realm.objects(Dog).filter("color = '棕黄色' AND name BEGINSWITH 'B'").sorted("color")
    
    

    创建对象

    var myDog = Dog()
    和swift新建对象的方法一致

    创建数据库

    通过调用 Realm()会在应用文件夹下的一个名为“default.realm”的文件,realm.path来获取realm数据库地址,可以使用Realm Browser进行查看

    配置realm

    通过Realm.Configuration您可以配置诸如 Realm 文件在何处存储之类的信息。苹果推荐<Application_Home>/Library/Caches目录下,
    在生成 Realm 文件的代码处,您需要结尾对文件进行压缩拷贝(参见 Realm().writeCopyToPath(_:encryptionKey:))。 这有助于减少 Realm 的文件体积,让您发布的应用体积更小;

    删除数据库

    大多数文件可以通过removeItemAtPath删除,但是您必须要采取额外的操作,来确保没有任何活跃的 Realm 对象在删除过程中访问数据库。Realm 实例将会在它们的整个生命周期中,持有对数据库的连接。限制 Realm 实例生命周期的方法就是使用 autorelease pool 将其使用操作包含在其中。所有 path 指向您想要删除的 Realm 文件的 Realm 实例,都必须要在删除操作执行前被释放掉。

    4. 多线程

    Realm 通过确保每个线程始终拥有 Realm 的一个快照,以便让并发运行变得十分轻松。您唯一需要注意的一件事情就是不能让多个线程都持有同一个 Realm 对象的 实例 。如果定期刷新 Realm 失败的话,就可能会导致某些事务的版本变为“锁定(pinned)”状态,阻止 Realm 重用该版本的硬盘空间,从而导致文件尺寸变大。
    不支持 跨线程共享Realm 实例。 Realm 实例要访问相同的 Realm 文件还必须使用相同的 Realm.Configuration。
    当你同时进行多个写操作的时候,他们会相互阻塞,阻塞住他们所运行的线程。因此您必须要为每一个您想要执行读取或者写入操作的线程或者dispatch队列创建一个 Realm 实例。所以应当考虑在 UI 之外的线程中来进行操作。另外需要注意的是,在进行写事务的时候,读操作并不会造成阻塞。这非常有用,尤其是当你在后台进行写操作的时候,用户可能会在不同界面切换,而这时候可以进行读操作
    Realm 对象在每个线程中都应该只被创建一次,因为它不是线程安全的,不能在不同的线程中共享。如果你想要在另一个线程中执行写操作,那么就需要创建一个新的 Realm 对象。
    建议你使用常用的,也是最有效的方案, 将所有写入放到一个单独的进程中。

    5. 其他

    通知

    通过调用 addNotificationBlock 方法进行通知注册后,无论哪个 Realm, Results 或者 List 对象更新,都可以得到通知。Results 以及 List 实例在注册的时候,会使用初始的集合来调用闭包,然后当每次写事务对集合或者包含在其中的任何事物进行改变之后,会再次调用一遍此闭包。

    加密

    • 在iOS平台中,通过使用 NSFileProtection API 就可以花费极小的代价完成 Realm 的文件加密。
    • 使用realm官方的加密方法:
    // 产生随机密钥
    let key = NSMutableData(length: 64)!
    SecRandomCopyBytes(kSecRandomDefault, key.length,
        UnsafeMutablePointer<UInt8>(key.mutableBytes))
    
    // 打开加密文件
    let config = Realm.Configuration(encryptionKey: key)
    do {
      let realm = try Realm(configuration: config)
      // 和往常一样使用 Realm 即可
      let dogs = realm.objects(Dog).filter("name contains 'Fido'")
    } catch let error as NSError {
      // 如果密钥错误,`error` 会提示数据库不可访问
      fatalError("Error opening realm: \(error)")
    }
    

    参考资料

    Realm Swift官方文档

    
                                    —— 念念不忘,必有回响
    

    @author fharmony Email Weibo or Github

    相关文章

      网友评论

          本文标题:移动开发数据库篇 之 SwiftRealm(上)

          本文链接:https://www.haomeiwen.com/subject/gqnplttx.html