Realm入门指北

简介

接触Realm已经有一段时间了,但是一直忙着项目,一直没有时间做一下笔记。趁着项目闲着之际,我开始着手记录我自己使用Realm过程遇到的坑。Realm是一个跨平台的数据库,就拿iOS来说,数据库常用的几种无非是Sqlite、FMDB、CoreData这几种,每一种数据库都在某些方面有着特别的优势。对于coreData,在每次使用的时候都要创建一大堆的代码,个人是累觉不爱。而对于Sqlite是基于C语言的,用起来也是相对麻烦,FMDB是基于Sqlite的封装,用起来还相对友好一点,但是还是要写一大堆的sql语句,但是无可否认的是,在API上FMDB还是蛮简单上手的。但是今天重点介绍的是Realm.

Realm是由Y Combinator孵化的创业团队开源出来的一款可以用于iOS(同样适用于Swift&Objective-C)和Android的跨平台移动数据库。目前最新版是Realm 2.0.2,支持的平台包括Java,Objective-C,Swift,React Native,Xamarin。

安装方法主要有四种(在这就不做说明)
1.Dynamic Framework(动态库)
2.CocoaPod
3.Carthage(仅支持iOS8以上)
4.Static Framework

Realm 中的相关术语

为了能更好的理解Realm的使用,先介绍一下涉及到的相关术语。

RLMRealm:Realm是框架的核心所在,是我们构建数据库的访问点,就如同Core Data的管理对象上下文(managed object context)一样。出于简单起见,realm提供了一个默认的defaultRealm( )的便利构造器方法。

RLMObject:这是我们自定义的Realm数据模型。创建数据模型的行为对应的就是数据库的结构。要创建一个数据模型,我们只需要继承RLMObject,然后设计我们想要存储的属性即可。

关系(Relationships):通过简单地在数据模型中声明一个RLMObject类型的属性,我们就可以创建一个“一对多”的对象关系。同样地,我们还可以创建“多对一”和“多对多”的关系。

写操作事务(Write Transactions):数据库中的所有操作,比如创建、编辑,或者删除对象,都必须在事务中完成。“事务”是指位于write闭包内的代码段。

查询(Queries):要在数据库中检索信息,我们需要用到“检索”操作。检索最简单的形式是对Realm( )数据库发送查询消息。如果需要检索更复杂的数据,那么还可以使用断言(predicates)、复合查询以及结果排序等等操作。

RLMResults:这个类是执行任何查询请求后所返回的类,其中包含了一系列的RLMObject对象。RLMResults和NSArray类似,我们可以用下标语法来对其进行访问,并且还可以决定它们之间的关系。不仅如此,它还拥有许多更强大的功能,包括排序、查找等等操作。

Realm 的基本使用

1.创建数据库
  • 1.使用系统默认的数据库
  • 2.自定义数据库(代码实现的是自定义的数据库)

Object-C

RLMRealm *realm = [RLMRealm defaultRealm];
 - (BOOL) initRealm {
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
                       URLByAppendingPathComponent:[NSString stringWithFormat:@"Message%lu",(unsigned long)self.messageType]]
                      URLByAppendingPathExtension:@"realm"];
    debugLog(@"Realm file path: %@", config.fileURL);
    NSError *error;
    _realm = [RLMRealm realmWithConfiguration:config error:&error];
    if (nil != error) {
        NSLog(@"Create Realm Error");
        return NO;
    }
    debugLog(@"create realm success");
    return YES;
}

Swift

    // MARK: - 初始化Rleam数据库
    func createDataBase() {
        var config = Realm.Configuration()
        config.fileURL = config.fileURL?.deletingLastPathComponent().appendingPathComponent("HJQ").appendingPathExtension("Realm")
        var realm: Realm?
        do {
           realm =  try Realm.init(configuration: config)
        } catch  {
            debugLog(error)
        }
        debugLog(realm)
    }
2.建表

Object-C

#import <Foundation/Foundation.h>
#import <Realm/Realm.h>

@interface UserMessageList : RLMObject

@property NSString *title;
@property NSInteger linkType;
@property NSInteger messageId;
@property BOOL readStatus;
@property NSString *content;
@property long long createTime;
@property NSString *picUrl;

@end
RLM_ARRAY_TYPE(UserMessageList);

@interface GFBUserMessageMD : RLMObject

@property NSString *username;
@property RLMArray<UserMessageList> *userMessageList;

@end
RLM_ARRAY_TYPE(GFBUserMessageMD);

注意,RLMObject 官方建议不要加上 Objective-C的property attributes(如nonatomic, atomic, strong, copy, weak 等等)假如设置了,这些attributes会一直生效直到RLMObject被写入realm数据库。

RLM_ARRAY_TYPE宏创建了一个协议,从而允许 RLMArray<GFBUserMessageMD>语法的使用。如果该宏没有放置在模型接口的底部的话,您或许需要提前声明该模型类。

关于RLMObject的的关系

1.对一(To-One)关系

对于多对一(many-to-one)或者一对一(one-to-one)关系来说,只需要声明一个RLMObject子类类型的属性即可

2.对多(To-Many)关系(重点介绍)
通过 RLMArray类型的属性您可以定义一个对多关系。如上面代码例子,@property RLMArray<UserMessageList> *userMessageList;

3.反向关系(Inverse Relationship)

#import "GFBUserMessageMD.h"

@implementation GFBUserMessageMD
// 为了保证表的唯一性,设置主键
+ (NSString *)primaryKey {
    return @"username";
}

@end
@implementation UserMessageList

@end

Swift

import UIKit
import RealmSwift
>
class UserMessageMD: Object {
    dynamic var title: String?
    dynamic var messageID: String!
}
>
class UserMD: Object {
    dynamic var userID: String!
    dynamic var name: String!
    >
    // List 是个泛型
    var userMessages = List<UserMessageMD>()
    >
    // MARK: - 设置主键
    override static func primaryKey() -> String? {
        return "userID"
    }
}
3.数据的插入

Object-C

- (void) insertOrCreateData:(GFBSysMessageListMD *)md {
    GFBUserMessageMD *userMD;
    NSString *userId = [QFUserInfo shareInfo].username;
    if (! userId) {
        return;
    }
    // 查询当前是否有这个表
    if ([GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId]) {
        userMD = [GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId];
    }else {
        userMD = [GFBUserMessageMD new];
        userMD.username = userId;
    }
    [_realm transactionWithBlock:^{
        for (int i = 0; i < md.data.content.count; i++) {
            SysMessageListContent *model = md.data.content[i];
            UserMessageList *userMessageMD;
            NSPredicate *pred = [NSPredicate predicateWithFormat:@"messageId = %li",model.id];
            if([userMD.userMessageList indexOfObjectWithPredicate:pred] != NSNotFound) { // 如果该数据已经存在则无需重新插入
                NSUInteger index = [userMD.userMessageList indexOfObjectWithPredicate:pred];
                userMessageMD = userMD.userMessageList[index];
                debugLog(@"我是查询的结果%lu",index);
            }else{
                // 插入新的数据
                userMessageMD = [UserMessageList new];
                userMessageMD.title = model.title;
                userMessageMD.messageId = model.id;
                userMessageMD.content = model.content;
                userMessageMD.createTime = model.createTime;
                userMessageMD.readStatus = NO;
                userMessageMD.linkType = model.linkType;
                userMessageMD.picUrl = model.picUrl;
                [userMD.userMessageList addObject:userMessageMD];
            }
        }
        [GFBUserMessageMD createOrUpdateInRealm:_realm withValue:userMD];
    }];
}

Swift

// MARK: - 建表插入数据
    func insertData() {
        let realm = try! Realm()
        // 通过主键查找到对应的数据
        var userMD = realm.object(ofType: UserMD.self,forPrimaryKey: "")
        if userMD == nil {
            userMD = UserMD()
        }
        let messageID = "10000"
        try! realm.write {
            var userMessageMD: UserMessageMD? = nil
            let pred = NSPredicate(format: "messageID = \(messageID) ")
            let resultIndex = userMD!.userMessages.index(matching: pred)
            if resultIndex != NSNotFound { // 已经存在
                userMessageMD = userMD!.userMessages[resultIndex!]
            }else {
                userMessageMD = UserMessageMD()
                // 不存在则继续追加
                userMD?.userMessages.append(userMessageMD!)
            }
            realm.add(userMD!, update: true)
        }
    }
4.数据的更新
- (void) updateReadStatus:(NSInteger) index {
    GFBUserMessageMD *userMD;
    NSString *userId = [QFUserInfo shareInfo].username;
    if (! userId) {
        return;
    }
    // 查询当前是否有这个表
    if ([GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId]) {
        userMD = [GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId];
    }
    if (userMD) {
        [_realm transactionWithBlock:^{
            UserMessageList *userMessageMD = userMD.userMessageList[index];
            userMessageMD.readStatus = YES;
            [GFBUserMessageMD createOrUpdateInRealm:_realm withValue:userMD];
        }];
    }
}
5.数据的查询

Object-C

// 查找所有的数据
- (void) queryAllData {
    GFBUserMessageMD *userMD;
    NSString *userId = [QFUserInfo shareInfo].username;
    if (! userId) {
        return;
    }
    // 查询当前是否有这个表
    if ([GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId]) {
        userMD = [GFBUserMessageMD objectInRealm:_realm forPrimaryKey:userId];
    }
    if (userMD) {
        debugLog(@"当前存在的数据%@",userMD.userMessageList);
    }
}

Swift

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

推荐阅读更多精彩内容