FMDB 使用方法【转】

2022-10-18  本文已影响0人  小船2022

(一)Realm简单介绍

1.什么是Realm

Realm 是由美国YCombinator孵化的创业团队历时几年打造的第一款针对移动设备设计的数据库。是一个跨平台的移动数据库引擎,目前支持iOS、Android平台,同时支持Objective-C、Swift、Java、React Native、Xamarin等多种编程语言。Realm并不是对SQLite或者CoreData的简单封装, 是由核心数据引擎C++打造,是拥有独立的数据库存储引擎,可以方便、高效的完成数据库的各种操作

2.Realm的特性

a.移动设备支持:Realm是第一个针对手机平板和可穿戴设备涉及的数据库,基本全平台支持。

b.简单:Realm的安装和借入简易,不同于Core Data,不需要开发者配置模型层结构,从开始接触到上手使用,只需要短短几分钟而已。

c.现代:关系型数据库,支持泛型。

d.快速:官方称比SQLite常规操作要快。

e.跨平台:同时支持多个平台,节省资源。

3.Realm的资源

官方文档:[https://realm.io](https://links.jianshu.com/go?to=https%3A%2F%2Frealm.io) (学习的首选参考手册)

GitHub:[https://github.com/realm/realm-cocoa](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Frealm%2Frealm-cocoa)

可视化工具: Realm Browser

![image](https://img.haomeiwen.com/i2116934/77209a1edc365f1e.png?imageMogr2/auto-orient/strip|imageView2/2/w/208/format/webp)

如果需要调试, 可以通过NSHomeDirectory()打印出Realm数据库地址, 找到对应的Realm文件, 然后用Realm Browser可视化工具打开即可

Xcode 插件有助于创建Realm数据模型

![image](https://img.haomeiwen.com/i2116934/642f5587bfb56ddc.png?imageMogr2/auto-orient/strip|imageView2/2/w/238/format/webp)

(二)Realm的安装

(1)手动安装

a.* 要使用 Realm 数据库, 首先要导入 Realm.framework 这个框架, 从[Realm官网](https://links.jianshu.com/go?to=https%3A%2F%2Frealm.io)上可以下载,我使用的是*realm-objc-3.14.1* 这个版本, 下载解压完成后, 将iOS文件夹中的 static文件中的静态库拖到工程中

![image](https://img.haomeiwen.com/i2116934/d81fa0070aaa5526.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)

b.然后点击 Targets, 选择工程, 点击 Build Phases, 添加libz.tbd 和 libc++.tbd 两个库

![image](https://img.haomeiwen.com/i2116934/05f7565888eb0acb.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)

c.点击 plugin 文件中的项目, 运行,然后退出 XCode, 重启 XCode, 就可以安装成功插件, 我们就可以利用插件自动生成模型类

![image](https://img.haomeiwen.com/i2116934/985899664bd41024.png?imageMogr2/auto-orient/strip|imageView2/2/w/892/format/webp)

d.安装成功插件后, command + N 在新建文件的时候滑到最底端就可以看见Realm Model Object, 它就是Realm 数据库存储的模型对象, 你要存储的数据都是继承自这个类的. 所以我们新建 Realm Model Object 文件时, 就会自动帮我们建立一个.h 和.m 文件,就跟创建继承NSObject类是一样的

![image](https://img.haomeiwen.com/i2116934/5eaf2bb4af4a844e.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)

e.在用到的文件中引入#import <Realm/Realm.h> 即可使用

⚠️:官方文档介绍了四种安装说明,我只整理了一种最简单快速的方法

(2)工程中使用

(三)Realm定义的类

在`Realm`框架中,定义了二十个核心类、常量、枚举类型、协议等,常用的如:`RLMRealm`类、`RLMObject`类、`RLMResults`类等, 我们可以从`Realm`的[官方网站](https://links.jianshu.com/go?to=https%3A%2F%2Frealm.io%2Fdocs%2Fobjc%2Flatest%2Fapi%2FConstants.html)上查看所有的定义以及使用说明

1.Realm类

一个Realm类的对象可以认为是一个Realm数据库,Realm数据库既可以存储到硬盘上,也可以存储到内存中。Realm类是框架的核心类,如同FMDB中的FMDatabase ,Core Data管理对象的上下文managed object context一样

```

//获取默认的Realm数据库

+ (instancetype)defaultRealm;

//实例化一个realm数据库,根据配置参数获取对应的Realm数据库

+ (nullable instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error;

//根据指定的文件URL初始化一个Realm数据库

+ (instancetype)realmWithURL:(NSURL *)fileURL;

//对Realm 数据库进行读写操作之前,只能开启一个写事务

- (void)beginWriteTransaction;

//对Realm数据库进行读写操作完成之后,关闭对应的写事务

- (void)commitWriteTransaction NS_SWIFT_UNAVAILABLE("");

//没有足够的磁盘空间来保存写入或由于意外的I / O错误,此方法可能会失败, 并返回error信息

- (BOOL)commitWriteTransaction:(NSError **)error;

//在当前写入事务中提交所有写入操作,而不收到此写入事件的特定通知

- (BOOL)commitWriteTransactionWithoutNotifying:(NSArray<RLMNotificationToken *> *)tokens error:(NSError **)error;

//回滚在当前写入事务期间进行的所有写入并结束事务

- (void)cancelWriteTransaction;

//执行写入事务块内特定的操作

- (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block NS_SWIFT_UNAVAILABLE("");

- (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error;

//添加或更新一个对象

- (void)addObject:(RLMObject *)object;

//将现有对象添加或更新到Realm中, 有则更新没有则插入

- (void)addOrUpdateObject:(RLMObject *)object;

//添加或更新多个对象

- (void)addObjects:(id<NSFastEnumeration>)objects;

- (void)addOrUpdateObjects:(id<NSFastEnumeration>)objects;

//删除对象

- (void)deleteObject:(RLMObject *)object;

- (void)deleteObjects:(id)array;

- (void)deleteAllObjects;

```

2.  RLMObject类

    在Realm数据库中存储的都是RMObject对象,RLMObject类是所有可以存储在Realm数据库中的对象的根类。

    在RLMObject类中,我们可以添加属性,添加的属性类型可以支持如下类型:

    NSString:字符串

    NSInteger, int, long, float, double:数字型,注意没有CGFloat

    BOOL/bool:布尔型

    NSDate:日期型

    NSData:二进制字符型

    NSNumber<X>: 其中X必须RLMInt, RLMFloat, RLMDouble或 RLMBool类型

    RLMArray<X>: 其中X必须是RLMObject类的子类, 用于建模多对多关系

    RLMObject的子类,用于建模多对一关系

```

//创建RLMObject对象, 传入一个NSArray或NSDictionary实例来设置对象属性的值

- (instancetype)initWithValue:(id)value NS_DESIGNATED_INITIALIZER;

//获取RLMObject对象的类名

+ (NSString *)className;

//在Realm数据库中,获取该RLMObject类的所有对象

+ (RLMResults *)allObjects;

//根据查询条件返回满足条件的所有RLMObject类的对象

+ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ...;

//使用默认Realm中的给定主键检索此对象类型的单个实例

+ (nullable instancetype)objectForPrimaryKey:(nullable id)primaryKey;

//从指定的Realm返回此对象类型的所有对象

+ (nonnull RLMResults *)allObjectsInRealm:(nonnull RLMRealm *)realm;

//返回与指定Realm中给定谓词匹配的此对象类型的所有对象

+ (nonnull RLMResults *)objectsInRealm:(nonnull RLMRealm *)realm where:(nonnull NSString *)predicateFormat, ...;

```

3.  RLMResults类

    当我们执行一个查询操作后,查询出满足条件的RLMObject对象会存放在一个RLMResults对象中,RLMResults类是一个数组类型的数据结构,因此在其类定义中,提供了很多与数组类似的属性和方法。

```

//结果集合中的对象个数

@property (readonly, assign, nonatomic) NSUInteger count;

//结果集合中对象的类型

@property (readonly, assign, nonatomic) RLMPropertyType type;

//管理此结果集合的Realm对象

@property (readonly, nonatomic) RLMRealm *_Nonnull realm;

//结果集合中包含的对象的类名称

@property (readonly, copy, nonatomic, nullable) NSString *objectClassName;

//返回结果集合中的第一个对象

- (nullable RLMObjectType)firstObject;

//返回结果集合中的最后一个对象

- (nullable RLMObjectType)lastObject;

//根据索引index获取其中的某个对象

- (RLMObjectType)objectAtIndex:(NSUInteger)index;

//根据对象返回其索引

- (NSUInteger)indexOfObject:(RLMObjectArgument)object;

//返回与谓词匹配的结果集合中第一个对象的索引

- (NSUInteger)indexOfObjectWhere:(nonnull NSString *)predicateFormat, ...;

//返回与结果集合中给定谓词匹配的所有对象

- (RLMResults<RLMObjectType> *)objectsWhere:(NSString *)predicateFormat, ...;

//返回RLMResults从现有结果集合中排序的内容

- (RLMResults<RLMObjectType> *)sortedResultsUsingKeyPath:(NSString *)keyPath ascending:(BOOL)ascending;

//返回RLMResults与现有结果集合不同的内容

- (nonnull RLMResults<RLMObjectType> *)distinctResultsUsingKeyPaths:(nonnull NSArray<NSString *> *)keyPaths;

```

相关类的官方说明:[https://realm.io/docs/objc/latest/api/Classes.html](https://links.jianshu.com/go?to=https%3A%2F%2Frealm.io%2Fdocs%2Fobjc%2Flatest%2Fapi%2FClasses.html)

(四)Realm的使用

1.存储对象

对于RLMObject类型的对象,我们可以直接对创建的对象进行存储,第一步, 初始化对象

```

    //1.属性赋值

    Dog *dog1 = [[Dog alloc]init];

    dog1.name = @"perter1";

    dog1.age = 1;

    //将数组转化为对象

    Dog *dog2 = [[Dog alloc]initWithValue:@[@"perter2",@2]];

    //将字典转化成对象

    Dog *dog3 = [[Dog alloc]initWithValue:@{@"name":@"perter3",@"age":@3}];

```

第二步就是把RLMObject对象写入Realm数据库, 同样有三种方式

```

//默认数据库

    RLMRealm *realm = [RLMRealm defaultRealm];

    //增

    //第一种增加方式

    [realm beginWriteTransaction];

    [realm addObject:dog1];

    [realm commitWriteTransaction];

    //第二种增加方式

    [realm transactionWithBlock:^{

        [realm addObject:dog2];

        [realm addObject:dog3];

    }];

    //第三种增加方式

    [realm transactionWithBlock:^{

        [Dog createInRealm:realm withValue:@{@"name":@"perter4",@"age":@4}];

    }];

```

Note:如果有多个写入操作,建议将每个写入操作放进一个单独的子线程中

2.查询操作

Realm的查询条件可以使用==、<=、<、>=、>、!=、BETWEEN、CONTAINS 以及 ENDSWITH等多种操作符

```

//查

    //Realm的查询条件可以使用==、<=、<、>=、>、!=、BETWEEN、CONTAINS 以及 ENDSWITH等多种操作符 关系型运算符

    //第一种:全量查询

    RLMResults *result = [Dog allObjects];

    NSLog(@"查询结果 %@",result);

    Dog *dog5 = [[Dog alloc]initWithValue:@{@"name":@"perter5",@"age":@5}];

    [realm transactionWithBlock:^{

        [realm addObject:dog5];

    }];

    NSLog(@"查询结果 %@",result);//实时查询更新

    //第二种:条件查询

    result = [Dog objectsWhere:@"age < 2"];

    NSLog(@"查询结果 %@",result);

    //第三种:数组排序

    RLMResults *result1 = [result sortedResultsUsingKeyPath:@"age" ascending:YES];

    NSLog(@"查询结果 %@",result1);//对原有数组进行排序之后得到一个新的数组

    //第四种:链式查询

    RLMResults *result2 = [result1 objectsWhere:@"age<3"];

    NSLog(@"查询结果 %@",result2);

```

3.更新操作

需要修改的模型一定是被Realm所管理的模型, 而且已经和磁盘上的对象进行地址映射

```

//更新

    //第一种更改在原有基础上进行更改

    [realm transactionWithBlock:^{

        dog1.name = @"newName1";

        dog2.name = @"newName2";

    }];

    RLMResults *result3 = [Dog objectsWhere:@"age < 2"];

    Dog *currentDog = result3.firstObject;

    [realm transactionWithBlock:^{

        currentDog.name = @"titanking";

    }];

    //第二种是有主键的情况下使用 addOrUpdateObject 或则createInRealm 方法进行更新 不然会crash: reason: ''Dog' does not have a primary key and can not be updated'

//    Dog *dog11 = [[Dog alloc]initWithValue:@{@"name":@"dog11",@"age":@11}];

//    [realm transactionWithBlock:^{

//        [realm addOrUpdateObject:dog11];

//

//    }];

//    [realm transactionWithBlock:^{

//        [Dog createInRealm:realm withValue:@{@"name":@"dog12",@"age":@12}];

//    }];

//    RLMResults *result4 = [Dog allObjects];

//    NSLog(@"查询结果 %@",result4);

```

Note:当有主键的情况下, 使用Update方法

addOrUpdateObject会去先查找有没有传入的Student相同的主键,如果有,就更新该条数据

这里需要注意,addOrUpdateObject这个方法不是增量更新,所有的值都必须有,如果有哪几个值是null,那么就会覆盖原来已经有的值,这样就会出现数据丢失的问题

createOrUpdateInRealm:withValue这个方法是增量更新的,后面传一个字典,使用这个方法的前提是有主键

方法会先去主键里面找有没有字典里面传入的主键的记录,如果有,就只更新字典里面的子集;如果没有,就新建一条记录

用addOrUpdateObject 或则createInRealm 方法进行更新前提是必须有主键, 不然会crash: reason: ''Dog' does not have a primary key and can not be updated'

4.删除操作

```

//删除

    //第一种 根据条件查询

    RLMResults *result5 = [Dog objectsWhere:@"age = 1"];

    Dog *deleteDog = [result5 firstObject];

    [realm transactionWithBlock:^{

        [realm deleteObject:deleteDog];

    }];

    RLMResults *result6 = [Dog objectsWhere:@"age < 6"];

    for (Dog *dog in result6) {

        [realm transactionWithBlock:^{

            [realm deleteObject:dog];

        }];

    }

    //如果有主键根据主键进行查询 没有就会crash

//    Dog *keyDog = [Dog objectInRealm:realm forPrimaryKey:@1];

//    [realm transactionWithBlock:^{

//        [realm deleteObject:keyDog];

//    }];

    ```

Note:删除方法中涉及到的primaryKey字段的前提是必须有主键

5.Realm数据库机制

上面用到的获取realm对象的方式都是通过defaultRealm来获取默认配置的realm对象,而我们想要创建不同的Realm表则通过RLMRealmConfiguration配置进行操作

```

//配置Realm数据库

```

[self setDefaultRealmForUser:@"zhangsan"];

RLMRealm *newRealm = [RLMRealm defaultRealm];

```

```

-(void)setDefaultRealmForUser:(NSString *)username {

    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];

    config.fileURL = [[[config.fileURL URLByDeletingPathExtension] URLByAppendingPathComponent:username] URLByAppendingPathExtension:@"realm"];

    [RLMRealmConfiguration setDefaultConfiguration:config];

}

```

6.查看本地Realm数据库

找到本地Realm的路径,然后直接用Realm Browser 打开就可

![image](https://img.haomeiwen.com/i2116934/cb2bd14181981db1.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)

以上几种情况是比较常见的,后期还会有更新补充,如有错误不吝赐教

感谢大神文档:[https://www.jianshu.com/p/f415d07bc446](https://www.jianshu.com/p/f415d07bc446)

FMDB 使用方法:[https://www.jianshu.com/p/7958d31c2a97](https://www.jianshu.com/p/7958d31c2a97)

作者:123456789q

链接:https://www.jianshu.com/p/73b1f509a41f

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读