美文网首页
FMDB 使用方法【转】

FMDB 使用方法【转】

作者: 小船2022 | 来源:发表于2022-10-18 11:12 被阅读0次

    (一)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

    来源:简书

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

    相关文章

      网友评论

          本文标题:FMDB 使用方法【转】

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