iT邦幫忙

3

[Swift] Realm.io 資料庫介紹 - 其之一:初探CRUD

[官方網站]
Realm.io

[前言]
如果你厭倦了手機使用sqlite資料庫的很多處理方式……
如果你想要一個輕鬆簡單易用的物件封裝式資料庫………
如果你想要有一個讀取效率極佳的資料庫……
如果你希望能夠輕鬆的牽移結構……
如果你想看到一個強大的關連式行動資料庫……
Realm,會是你極佳的選擇。

[支援語言]
swift、Objective-C、Android java、React native、Xamarin C#

[本篇介紹]
語言:Swift 3
資料庫封裝:Realm object
資料庫:Realm

[歷程&介紹]
之前在開發app時,本來想說就使用swift的coredata。可是說真的,coredata要說強大嘛……
是很強大。但是他的寫法封裝說實在的,一點也不優。
在swift 2.0~2.2時,還發生過設定完coredata後,一做結構遷移,整個資料庫的資料就不見了。
還是去看到國外有人在AppDelegate.swift中改了一些code才得以順利的讓遷移後資料不致於不見。
到了swift 3時,我一直在想有沒有人針對sqlite有很好的處理模式或是優化coredata的封裝。
就在那個時候我發現了Realm。
一開始我以為Realm只是另一套sqlite的處理封裝。
直到我在官網好好研究後才發現:他是獨立的資料庫跟資料庫引擎。
在看完官方的介紹,他的操作封裝模式深深吸引了我。
因為他操作的方式實在是簡化到已經非常優的地步了。
處理個資料庫只要少少的幾行code就可以做到非常強大的CRUD。
在其後本來還在為了order by或是group by這一類的東西煩惱著時。
卻發現他有非常強大的RelationShips。
而且更強大的是:可以直接使用關連物件進行CURD行為……
這在往後會慢慢的介紹他。

我沒有很詳細的了解Realm的歷程,貌似是2014年發跡的。
是很新的資料庫。
有人實際測試過他和sqlite的比較。
寫入速度是sqlite的1/2(對!他寫入的速度比sqlite慢了一些。)
讀取速度卻是sqlite的3倍(所以寫入慢或許就是為了優化讀取的關係吧……個人猜測)

[安裝]
官方提供的安裝方式有三種:
1.下載Realm framework,然後匯入到專案 - 麻煩,因為要改一些設定檔。
2.Cocoapods安裝 - 推薦。不用去動設定檔。
3.Carthage - 沒用過。但用過的人是說如果沒使用Cocoapods管理套件的話,可以選用這種方式。

因為我個人都是用Cocoapods來管理套件,所以這邊就只講Cocoapods的安裝。

基本上其實就只要去podfile加上如下的內容:(每個人的pod設定都略有不同,你明白就好)

def shared_pods
    pod 'RealmSwift', '~> 2.4.2'
end

target 'your Project' do
    shared_pods
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = ‘3.0’ #如果是swift 2,應該要改成2.3
    end
  end
end

修改好podfile後再執行pod install即可。

這樣子,就把Realm設定到你的專案了。

[設定資料庫結構]
安裝好之後,你要開始設置你的資料庫結構。
跟coredata的表單設定不同。Realm是直接寫物件封裝來設定結構的。
大致如下:
(我個人有個建議,就是table也就是class的名稱前面都加RLM_,這樣比較不會跟有些類別名稱混淆。)

import UIKit
import RealmSwift

class RLM_User : Object {

    private(set) dynamic var uuid:String = UUID().uuidString #這樣的設置就是自動產生uuid
    dynamic var name:String = ""
    dynamic var age:Int = 0
    dynamic var address:String = ""
    
    //設置索引主鍵
    override static func primaryKey() -> String {
        return "uuid"
    }
    
}

如上面的程式碼,class名稱就是table,屬性名稱就是column。
這邊要注意的是,屬性的型態可以有以下幾種:
Bool, Int, Int8, Int16, Int32, Int64, Double, Float, String, NSDate, NSData
另外第一個的:
private(set) dynamic var uuid:String = UUID().uuidString
意思很簡單:准讀不准寫。
因為他是自動產生uuid,不允許之後去做任何變動。
另外提示一個他跟mysql不同的地方。
Realm基本上取資料是有根據先後順序的。
mysql如果你沒有設定好取資料規則的話。取資料的順序未必是按照你寫入的順序。
也是基於這一點,所以其實你沒有需要設定資料順序的欄位的必要性。
而且在之後他會有很強大的關連物件List來幫你很好的管理「群組」和「資料順序」
(今天先不會介紹關連的強大)

[寫入資料]
當你設定好以上的內容後,接下來就是要寫入資料庫了。
我們在專案中如下編寫code,就可以做到寫入的動作。

import UIKit
import RealmSwift

class ViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.writeData()
    }
    
    func writeData() {
        let realm = try! Realm()
        let user = RLM_User()
        user.name = "Sam"
        user.age = 40
        user.address = "Taipei"
        
        try! realm.write {
            realm.add(user)
        }
    }

}

執行這段程式碼,就可以將資料寫入realm資料庫了。
註:接下來的code我不重複展示整個class,僅以階段的func來展示。
操作練習時請記得自行呼叫func。

[讀取資料]
realm的資取資料真的只能用「簡單到不行」來形容。
可由以下的code看出來。

func readResults(){
    let realm = try! Realm()
    let users = realm.objects(RLM_User.self) #get users:Type is Results<RLM_User>
    if users.count > 0 {
        print(users[0].name)
    }
}

短短二行,就可以取出user的全部資料放進users。
這邊要注意的是他的資料格式叫做Results<RLM_User>
Results本身是一個陣列,裡面放的是RLM_User的物件。
但他並非是Array()或是NSArray()這一點要稍微注意。
(本篇暫不介紹條件式讀取)

[更新資料]
當你取出資料時,可能需要變動內容再回存。
可參照以下的code來設定更新:

func updateData(){
    let realm = try! Realm()
    if let user = realm.objects(RLM_User.self).filter("name = 'Sam'").first {
        user.age = 20 #年齡詐欺
        try! realm.write {
            realm.add(user,update:true)
        }
    }
}

[刪除資料]
最後就是CURD中的刪除了。
其實跟更新的方法類似,只是最後執行的東西不同。

//單一資料刪除
func deleteData(){
    let realm = try! Realm()
    if let user = realm.objects(RLM_User.self).filter("name = 'Sam'").first {
        try! realm.write {
            realm.delete(user)
        }
    }
}

//複合條件刪除
func deleteResults(){
    let realm = try! Realm()
    let users = realm.objects(RLM_User.self).filter("name = 'Eagle'")
    try! realm.write {
        realm.delete(users) #砍了老鷹……等一下他要來追殺我了!
    }
}

危險:realm其實還有一個方法,叫做deleteAll....顧名思義……使用前請想清楚!
註:要注意的是,realm刪掉資料時並不會刪除檔案的磁區。但他會保留下來供日後其他新增的資料快速寫入。

以上,就是Swift的Realm初探CRUD
等第二篇出來時,會講結構遷移(很重要,卻也很簡單)

[補充]
就在剛剛注意到一個之前沒注意到的update
基本上如果你已經取出資料,是可以直接改資料的。只要寫在realm.write內即可。

func updateData (){
    let realm = try! Realm()
    if let data = realm.objects(RLM_User.self).filter("name = 'Sam'").first {
        try! realm.write {
            data.address = "New Taipei City"
        }
    }
}

realm.add(xxx,update:true)的用法其實是資料不存在是會新增。
而資料存在時會更新。

--
[目次]
[Swift] Realm.io 資料庫介紹 - 其之一:初探CRUD
[Swift] Realm.io 資料庫介紹 - 其之二:Migrations 遷移
[Swift] Realm.io 資料庫介紹 - 其之三:查詢、排序、鍵結、自動更新、筆數


尚未有邦友留言

立即登入留言