美文网首页ios 知识小集iOS技术篇iOS数据库相关
CoreData,SQLite,Realm的认识和使用

CoreData,SQLite,Realm的认识和使用

作者: Fly_Sunshine_J | 来源:发表于2016-10-26 13:53 被阅读929次

    一、概念

    CoreData介绍

    CoreData是苹果在iOS5推出来用于数据持久化的API,相对于SQLite来说,CoreData省去了写SQL语句的麻烦,大家都知道在Xcode里面写SQL语句特别容易出错,只要出错这个bug我们估计要找半天吧!CoreData提供数据--OC对象映射关系来实现数据和对象的管理,这样就无需任何的SQL语句来操作数据库。

    SQLite介绍

    SQLite也是一款轻量级的数据库,而且还是世界上使用最多的数据库引擎,而且是开源的(官网)和跨平台的,这个才是王道。

    Realm

    Realm是个比较新的产品,官网出来的时间也是在2014年,同时Realm也是跨平台的移动数据库,不仅支持Android,iOS还支持macOS,Linux,ReactNative和Xamarin,而且官方的文档给的特别的清楚,还有中文版的,Realm的处理速度上和CoreData、SQLite的速度并不差,但是他的复杂程度相对于CoreData和SQLite来说就更简单。官网文档

    二、CoreData(推荐库:MagicalRecord)

    核心类与结构

    NSManagedObjectContext(数据上下文)

    • 对象管理上下文,负责数据的实际操作
    • 用于数据的增、删、查、改

    NSPersistentStoreCoordinator(持久化存储助理)

    • 相当于数据库的连接器
    • 用于设置存储的方法和存储的位置

    NSManagedObjectModel(数据模型)

    • 数据库所有表格或数据结构,包含各实体的定义信息
    • 作用:添加实体的属性,建立属性之间的关系

    NSManagedObject(被管理的数据记录)

    • 数据库中的表格记录

    NSEntityDescription(实体结构)

    • 相当于表格结构

    NSFetchRequest(数据请求)

    • 相当于查询语句

    CoreData结构图:

    1.结构图

    从上面的图中我们可以看到CoreData有三个功能部分:
    上面的部分NSManagedObjectContext是管理的模型部分,由NSManagedObjectContext管理NSManagedObject,下面的部分是NSPersistentStore是负责实现本地持久化的部分,负责和SQL数据库交互,中间的NSPersistentStoreCoordinator调度器作用是NSManagedObjectContext上部分存储的数据交给中间的调度器NSPersistentStoreCoordinator,由调度器用具体的持久化对象NSPersistentStore来操作对应的数据库文件。

    实现过程:

    1.创建工程(本文不用这种方式,因为可能你的程序写到一半了,才想用CoreData,或者旧的项目没有用CoreData,这时候再创建新工程,copy代码,不敢往下想会浪费多少时间...):

    创建工程时,会有一个勾选Use Core Data的选项,如果你勾选了这个选项,会在你的项目里自动生成一些文件、对象和方法:

    2.勾选Use Core Data
    1. 生成的文件是一个和项目同名的.xcdatamodeld的模型文件,在这里可以创建实体,再根据创建的实体创建模型对象。
    3.生成的模型文件

    2.AppDelegate.h中新增的代码

    //
    //  AppDelegate.h
    //  CoreDataTest
    //
    //  Created by vcyber on 16/10/24.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    //数据的上下文
    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
    //数据模型
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
    //持久化存储助理
    @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
    //保存当前上下文中的数据
    - (void)saveContext;
    //数据库的存储位置
    - (NSURL *)applicationDocumentsDirectory;
    
    @end
    

    3.AppDelegate.m中新增的代码(相信大家都能看懂中间的注释,写的非常的清楚)

    - (void)applicationWillTerminate:(UIApplication *)application {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        // Saves changes in the application's managed object context before the application terminates.
        [self saveContext];
    }
    #pragma mark - Core Data stack
    
    @synthesize managedObjectContext = _managedObjectContext;
    @synthesize managedObjectModel = _managedObjectModel;
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
    
    - (NSURL *)applicationDocumentsDirectory {
        // The directory the application uses to store the Core Data store file. This code uses a directory named "com.vcyber.CoreDataTest" in the application's documents directory.
        return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    }
    
    - (NSManagedObjectModel *)managedObjectModel {
        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
        if (_managedObjectModel != nil) {
            return _managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataTest" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return _managedObjectModel;
    }
    
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }
        
        // Create the coordinator and store
        
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataTest.sqlite"];
        NSError *error = nil;
        NSString *failureReason = @"There was an error creating or loading the application's saved data.";
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
            // Report any error we got.
            NSMutableDictionary *dict = [NSMutableDictionary dictionary];
            dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
            dict[NSLocalizedFailureReasonErrorKey] = failureReason;
            dict[NSUnderlyingErrorKey] = error;
            error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
            // Replace this with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        
        return _persistentStoreCoordinator;
    }
    
    - (NSManagedObjectContext *)managedObjectContext {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
        if (_managedObjectContext != nil) {
            return _managedObjectContext;
        }
        
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (!coordinator) {
            return nil;
        }
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        return _managedObjectContext;
    }
    
    #pragma mark - Core Data Saving support
    
    - (void)saveContext {
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }
    

    1.创建工程

    1. 创建和上面只是不勾选Use Core Data点击创建
    2. command+N创建新文件iOS->Core Data->Data Model->Next,这一步创建的文件相当于勾选Use Core Data自动创建的.xcdatamodeld文件。
    4.创建 Data Model

    3.创建后的项目目录

    5.项目目录

    4.创建实体(Entity)
    点击上面创建的DataModel.xcdatamodeld文件,进入可视化创建实体界面

    6.创建实体的界面

    5.添加关系
    我在该实体中添加了两个实体, 一个学生实体Student和一个书本实体Book,添加关系:
    Student实体关系添加步骤详图:

    7.Student添加关系图

    Book实体添加关系步骤和上面基本相同,注意以下的红圈:

    8.Book添加关系图

    上面完成后,你点击Student类在student的最后选项inverse就会有值books,你点击右下角的style可以看到两个实体的关系如下图:

    9.实体间的关系图

    6.创建对象类文件
    command+N创建新文件iOS->Core Data-> NSManagedObject subclass ->Next -> Select Data Model ->Next -> Selcet Entity -> Next -> Create, 创建后的工程目录


    10.工程目录

    7.点击Student+CoreDataProperties.h文件里面有属性和方法,但是这里面的方法全部都没有实现,根据这些函数的命名大家应该都知道什么意思, 而且这些函数的生成和图7中To Many下面的Ordered的勾选有关系, 如果不勾选不会有那么多的函数,而且这个里面books用的是NSOrderedSet,保证唯一性和一对多的关系

    #import "Student.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Student (CoreDataProperties)
    
    @property (nullable, nonatomic, retain) NSString *name;
    @property (nullable, nonatomic, retain) NSNumber *age;
    @property (nullable, nonatomic, retain) NSOrderedSet<Book *> *books;
    
    @end
    
    @interface Student (CoreDataGeneratedAccessors)
    
    - (void)insertObject:(Book *)value inBooksAtIndex:(NSUInteger)idx;
    - (void)removeObjectFromBooksAtIndex:(NSUInteger)idx;
    - (void)insertBooks:(NSArray<Book *> *)value atIndexes:(NSIndexSet *)indexes;
    - (void)removeBooksAtIndexes:(NSIndexSet *)indexes;
    - (void)replaceObjectInBooksAtIndex:(NSUInteger)idx withObject:(Book *)value;
    - (void)replaceBooksAtIndexes:(NSIndexSet *)indexes withBooks:(NSArray<Book *> *)values;
    - (void)addBooksObject:(Book *)value;
    - (void)removeBooksObject:(Book *)value;
    - (void)addBooks:(NSOrderedSet<Book *> *)values;
    - (void)removeBooks:(NSOrderedSet<Book *> *)values;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    8.AppDelegate的处理(其实可以是用单例处理,这里我就不用了,有兴趣的同学可以试一下)

    #import <UIKit/UIKit.h>
    #import <CoreData/CoreData.h>
    
    @interface AppDelegate : UIResponder <UIApplicationDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    
    //数据的上下文
    @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
    //数据模型
    @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
    //持久化存储助理
    @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
    //保存当前上下文中的数据
    - (void)saveContext;
    
    @end
    
    @synthesize managedObjectContext = _managedObjectContext;
    @synthesize managedObjectModel = _managedObjectModel;
    @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
    
    - (NSManagedObjectModel *)managedObjectModel {
    
        if (_managedObjectModel != nil) {
            return _managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return _managedObjectModel;
    }
    
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }
        
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        NSURL *storeURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"CoreDataTest.sqlite"];
        NSError *error = nil;
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
            NSLog(@"Unresolved error %@", error.localizedDescription);
        }
        
        return _persistentStoreCoordinator;
    }
    
    - (NSManagedObjectContext *)managedObjectContext {
    
        if (_managedObjectContext != nil) {
            return _managedObjectContext;
        }
        
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (!coordinator) {
            return nil;
        }
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        return _managedObjectContext;
    }
    
    - (void)saveContext {
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                NSLog(@"Unresolved error %@", error.localizedDescription);
    
            }
        }
    }
    

    9.ViewController.m文件的处理,这里添加了10000条数据,和读取10000条数据.

    //
    //  ViewController.m
    //  CoreDataTest
    //
    //  Created by vcyber on 16/10/24.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import "ViewController.h"
    #import "AppDelegate.h"
    #import "Student.h"
    #import "Book.h"
    
    @interface ViewController ()
    
    @property (nonatomic, strong) AppDelegate *appDelegate;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        _appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    - (IBAction)save:(UIButton *)sender {
        
        NSManagedObjectContext *context = self.appDelegate.managedObjectContext;
        NSLog(@"save start");
        for (int i = 0; i < 10000; i++) {
            NSEntityDescription *entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:context];
            //创建学生对象
            Student *stu = [[Student alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
            stu.name = [NSString stringWithFormat:@"张三%d", i];
            NSEntityDescription *bEntity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:context];
            //创建Book对象
            Book *book = [[Book alloc] initWithEntity:bEntity insertIntoManagedObjectContext:context];
            book.title = @"红楼梦";
            //添加Book对象
            [stu addBooksObject:book];
            
            //保存Student对象
            [_appDelegate saveContext];
        }
        NSLog(@"save end");
    }
    
    - (IBAction)read:(UIButton *)sender {
        
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
        NSArray *arr = [self.appDelegate.managedObjectContext executeFetchRequest:request error:nil];
        NSLog(@"read start");
        for (Student *stu in arr) {
            for (Book *b in stu.books) {
            
            }
        }
        NSLog(@"read end");
    }
    
    - (AppDelegate *)appDelegate {
        if (!_appDelegate) {
            _appDelegate = [UIApplication sharedApplication].delegate;
        }
        return _appDelegate;
    }
    
    @end
    

    三、SQLite(推荐库:FMDB)

    注意 使用sqlite3的时候不仅要导入头文件sqlite3.h还要在Build Phases中引入库libsqlite3.tdb(注意不是3.0)

    常用的API(C语言的函数)

    //打开数据库
    int sqlite3_open(
      const char *filename,   /* 数据库的路径(UTF-8编码) */
      sqlite3 **ppDb          /* 数据库地址*/
    );
    //关闭数据库
    int sqlite3_close(sqlite3*)  /*数据库*/
    
    //执行数SQL语句
    int sqlite3_exec(
      sqlite3*,                                  /* 一个打开的数据库 */
      const char *sql,                           /* SQL语句 */
      int (*callback)(void*,int,char**,char**),  /* 回调函数 */
      void *,                                    /* 回调函数的第一个参数 */
      char **errmsg                              /* 错误信息 */
    );
    //执行SQL语句,将结果存在stmt中
    int sqlite3_prepare_v2(
      sqlite3 *db,            /* 数据库指针 */
      const char *zSql,       /* SQL语句 */
      int nByte,              /*长度, -1代表不限制 */
      sqlite3_stmt **ppStmt,  /* 执行SQL语句后的结果集 */
      const char **pzTail     /* NULL */
    );
    //用于遍历查询结果
    int sqlite3_step(
    sqlite3_stmt*          /*结果集*/
    ) 
    //取结果集的列数
    int sqlite3_column_count(
    sqlite3_stmt *pStmt   /*结果集*/
    );
    //去结果集的列名
    const char * sqlite3_column_name(
    sqlite3_stmt*,     /*结果集*/
    int N                    /*第几列*/
    )
    //取某一列的值,后面的text根据存储的类型变化,可以是int, double等
    const unsigned char *sqlite3_column_text(
    sqlite3_stmt*,   /*结果集*/
    int iCol             /*第几列*/
    );
    

    对SQLite进行简单的封装(使用了单例)

    DataBaseManager.h文件

    //
    //  DataBaseManager.h
    //  SQLiteTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface DataBaseManager : NSObject
    
    + (instancetype)shareManager;
    
    //打开数据库
    - (BOOL)openDataBaseWithName:(NSString *)name;
    
    //关闭数据库
    - (BOOL)closeDB;
    
    /**
     *  创建表
     *
     *  @param name 表名
     *
     *  @return 创建是否成功
     */
    - (BOOL)createTableWithName:(NSString *)name;
    /**
     *  插入数据
     *
     *  @param sql sql语句
     *
     *  @return 是否插入成功
     */
    - (BOOL)insertDataWithSQL:(NSString *)sql;
    /**
     *  删除数据
     *
     *  @param sql SQL语句
     *
     *  @return 是否删除成功
     */
    - (BOOL)deleteDataWithSQL:(NSString *)sql;
    /**
     *  更新数据
     *
     *  @param sql SQL语句
     *
     *  @return 是否更新成功
     */
    - (BOOL)updataDataWithSQL:(NSString *)sql;
    /**
     *  查询数据
     *
     *  @param sql SQL语句
     *
     *  @return 查询结果
     */
    - (NSArray *)selectDataWithSQL:(NSString *)sql;
    /**
     *  查询数据
     *
     *  @param sql SQL语句
     *
     *  @return 是否有数据
     */
    - (BOOL)queryDataWithSQL:(NSString *)sql;
    
    @end
    

    DataBaseManager.m文件

    //
    //  DataBaseManager.m
    //  SQLiteTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import "DataBaseManager.h"
    #import <sqlite3.h>
    
    @interface DataBaseManager (){
        sqlite3 *db;
        NSString *dbName;
    }
    
    @end
    
    @implementation DataBaseManager
    
    + (instancetype)shareManager {
        static DataBaseManager *manager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [[DataBaseManager alloc] init];
        });
        return manager;
    }
    
    - (BOOL)openDataBaseWithName:(NSString *)name {
        if (db) {
            return YES;
        }
        dbName = name;
        NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:name];
        
        int err = sqlite3_open([path UTF8String], &db);
        return err == SQLITE_OK ? YES : NO;
    }
    
    - (BOOL)closeDB {
        int err = sqlite3_close(db);
        if (err == SQLITE_OK) {
            db = nil;
            return YES;
        }else {
            return NO;
        }
    }
    
    - (BOOL)createTableWithName:(NSString *)name {
        if ([self openDataBaseWithName:dbName]) {
            NSString *sql = [NSString stringWithFormat:@"create table if not exists %@ (id integer primary key autoincrement, name text, age integer);", name];
            char *err;
            int result = sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err);
            if (result == SQLITE_OK) {
                [self closeDB];
                return YES;
            }else {
                NSLog(@"%s", err);
                [self closeDB];
                return NO;
            }
        }else {
            
            return NO;
        }
    }
    
    - (BOOL)insertDataWithSQL:(NSString *)sql {
        
        return [self executeSQL:sql];
    }
    
    - (BOOL)deleteDataWithSQL:(NSString *)sql {
        return [self executeSQL:sql];
    }
    
    - (BOOL)updataDataWithSQL:(NSString *)sql {
        return [self executeSQL:sql];
    }
    
    - (NSArray *)selectDataWithSQL:(NSString *)sql {
        
        if ([self openDataBaseWithName:dbName]) {
            // 创建一个数据库的替身, 存储对数据库的所有操作
            sqlite3_stmt *stmt = nil;
            
            int result = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
    
            if (SQLITE_OK == result) {
                // 创建一个可变数组, 用于存储数据
                NSMutableArray *rows=[NSMutableArray array];
                // 当sql执行成功, 遍历数据
                // 循环遍历所有的结果, 每次遍历到一条数据, 都会返回sqlite_row, 如果没有数据了, 就不会返回SQLITE_ROW, 跳出循环
                while (SQLITE_ROW == sqlite3_step(stmt)) {
                    
                    // 取int类型的数据
                    int columnCount = sqlite3_column_count(stmt);
                    
                    // 创建一个可变字典, 用来存储数据
                    NSMutableDictionary *dic=[NSMutableDictionary dictionary];
                    
                    for (int i = 0; i < columnCount; i++) {
                        
                        // 在循环体中去按列取数据
                        // 取得列名
                        const char *name = sqlite3_column_name(stmt, i);
                        
                        // 取得某列的值
                        const unsigned char *value = sqlite3_column_text(stmt, i);
                        
                        // 将char *字符串转为NSString字符串
                        dic [[NSString stringWithUTF8String:name]] = [NSString stringWithUTF8String:(const char *) value];
                    }
                    
                    [rows addObject:dic];
                }
                // 销毁stmt替身, 把里面的操作和结果写入本地sqlite文件
                sqlite3_finalize(stmt);
                return rows;
            }else {
                return nil;
            }
            
        }else {
            
            return nil;
        }
    
    }
    
    - (BOOL)queryDataWithSQL:(NSString *)sql {
        NSArray *arr  = [self selectDataWithSQL:sql];
        return arr.count > 0 ? YES : NO;
    }
    
    - (BOOL)executeSQL:(NSString *)sql {
        char *err;
        if ([self openDataBaseWithName:dbName]) {
            int result = sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err);
            if (result == SQLITE_OK) {
                [self closeDB];
                return YES;
            }else {
                NSLog(@"%s", err);
                [self closeDB];
                return NO;
            }
        }else {
            
            return NO;
        }
    }
    
    @end
    

    四、Realm(官方API

    导入静态库

    1. 下载 Realm 的最新版本并解压;
    2. 将 Realm.framework从 ios/static/文件夹拖曳到您 Xcode 项目中的文件导航器当中。确保 Copy items if needed 选中然后单击 Finish
    3. 在 Xcode 文件导航器中选择您的项目,然后选择您的应用目标,进入到** Build Phases** 选项卡中。在 Link Binary with Libraries 中单击 + 号然后添加 libc++.tbdlibz.tbd

    Realm的使用

    • 创建数据库的API
    + (nonnull instancetype)defaultRealm
    
    + (nullable instancetype)realmWithConfiguration:(nonnull RLMRealmConfiguration *)configuration error:(NSError *_Nullable *_Nullable)error;onfiguration error:(NSError *_Nullable *_Nullable)error;
    
    + (nonnull instancetype)realmWithURL:(nonnull NSURL *)fileURL;
    
    • 增加数据模型类
      创建Student类和Book类, 继承自RLMObject。
      Realm忽略了Objective-C的property attributes(如nonatomic, atomic, strong, copy, weak 等等)。 所以,推荐在创建模型的时候不要使用任何的property attributes。

    Student.h

    //
    //  Student.h
    //  RealmTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import <Realm/Realm.h>
    #import "Book.h"
    @interface Student : RLMObject
    @property int num;
    @property NSString *name;
    @property int age;
    @property RLMArray<Book *><Book> *books;  //这里表示一对多的关系
    
    @end
    RLM_ARRAY_TYPE(Student)  //宏定义  定义RLMArray<Student>这个类型
    

    Student.m

    //
    //  Student.m
    //  RealmTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import "Student.h"
    
    @implementation Student
    //设置主键
    + (NSString *)primaryKey {
        return @"num";
    }
    
    //非空字段
    + (NSArray<NSString *> *)requiredProperties {
        return @[@"name"];
    }
    
    //设置默认值
    + (NSDictionary *)defaultPropertyValues {
        return nil;
    }
    
    //设置忽略字段  如果设置该字段将不会插入数据库
    + (NSArray<NSString *> *)ignoredProperties {
        return nil;
    }
    
    @end
    

    Book.h

    //
    //  Book.h
    //  RealmTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import <Realm/Realm.h>
    @class Student;
    
    @interface Book : RLMObject
    
    @property NSString *title;
    @property float price;
    @property Student *stu;     //这里表示一对多的关系
    
    @end
    RLM_ARRAY_TYPE(Book)  //宏定义  定义RLMArray<Book>这个类型
    

    Book.m

    //
    //  Book.m
    //  RealmTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import "Book.h"
    
    @implementation Book
    
    //设置默认值
    + (NSDictionary *)defaultPropertyValues {
        return nil;
    }
    
    //非空字段
    + (NSArray<NSString *> *)requiredProperties {
        return @[@"title"];
    }
    
    //设置忽略字段  如果设置该字段将不会插入数据库
    + (NSArray<NSString *> *)ignoredProperties {
        return nil;
    }
    
    @end
    
    • 初始化模型数据的方法
    /**
     *  初始化模型对象
     *
     *  @param value 可以是字典,数组, 但是字段一定要对应
     *
     *  @return 模型对象
     */
    - (instancetype)initWithValue:(id)value
    
    /**
     *  在默认的数据库中初始化模型对象
     *
     *  @param value 字典或数组, 但是字段要对应
     *
     *  @return 模型对象
     */
    + (instancetype)createInDefaultRealmWithValue:(id)value;
    
    /**
     *  初始化模型对象
     *
     *  @param realm 对应的数据库
     *  @param value 字典或数组
     *
     *  @return 模型对象
     */
    + (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value
    
    /**
     *  创建或者更新默认数据库中的数据, 只有定义主键的数据模型才可以调用
     *
     *  @param value 字典或数组
     *
     *  @return 模型对象
     */
    + (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value;
    
    /**
     *  创建或者更新对应数数据库中的数据, 只有定义主键的数据模型才可以调用
     *
     *  @param realm 对应的数据库
     *  @param value 字典或数组
     *
     *  @return 模型对象
     */
    + (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value;
    
    • 增、删、查、改

    1.事务中完成(增、删、改应该在事务开始和提交之间完成或者在block中完成)

    //开始事务
    - (void)beginWriteTransaction;
    
    //提交事务
    - (void)commitWriteTransaction NS_SWIFT_UNAVAILABLE("");
    
    //带有返回值的提交事务
    - (BOOL)commitWriteTransaction:(NSError **)error;
    
    //取消事务
    - (void)cancelWriteTransaction;
    
    //带有block的事务提交
    - (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block NS_SWIFT_UNAVAILABLE("");
    //带有block和返回值的事务提交
    - (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error;
    

    2.增、改(由RLMRealm对象完成)

    /**
    添加一条数据到Realm中
     */
    - (void)addObject:(RLMObject *)object;
    
    /**
    添加集合中的数据到Realm中      array是`NSArray` or `RLMResults`
     */
    - (void)addObjects:(id<NSFastEnumeration>)array;
    
    /**
     添加或者更新已有的某条数据
     */
    - (void)addOrUpdateObject:(RLMObject *)object;
    
    /**
     添加或者更新已有的集合中的数据       array是`NSArray` or `RLMResults`
     */
    - (void)addOrUpdateObjectsFromArray:(id)array;
    

    3.删(由RLMRealm对象完成)

    /**
    删除一条数据
     */
    - (void)deleteObject:(RLMObject *)object;
    
    /**
     删除一个或多个数据
     @param array  An `RLMArray`, `NSArray`, or `RLMResults` of `RLMObject`s (or subclasses) .
     */
    - (void)deleteObjects:(id)array;
    
    /**
    删除所有的数据
     */
    - (void)deleteAllObjects;
    

    4.查(由对应的模型类完成)

    #pragma mark -在默认数据库中的查询
    
    /**
     返回默认数据库所有的数据
     */
    + (RLMResults *)allObjects;
    
    /**
     条件查询
     */
    + (RLMResults *)objectsWhere:(NSString *)predicateFormat, ...;
    
    + (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args;
    
    + (RLMResults *)objectsWithPredicate:(nullable NSPredicate *)predicate;
    
    #pragma mark - 查询某一个数据库
    
    /**
    查询所有数据
     */
    + (RLMResults *)allObjectsInRealm:(RLMRealm *)realm;
    
    /**
    条件查询
     */
    + (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ...;
    
    + (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args;
    
    + (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(nullable NSPredicate *)predicate;
    
    
    • 这里附上ViewController里面的代码
    //
    //  ViewController.m
    //  RealmTest
    //
    //  Created by vcyber on 16/10/25.
    //  Copyright © 2016年 vcyber. All rights reserved.
    //
    
    #import "ViewController.h"
    #import <Realm/Realm.h>
    #import "Student.h"
    #import "Book.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"%@", [RLMRealm defaultRealm].configuration.fileURL);
    }
    
    - (IBAction)add:(UIButton *)sender {
        NSLog(@"save start");
        for (int i = 0; i < 10000; i++) {
            Student *stu = [[Student alloc] initWithValue:@{@"num": @(i), @"name": [NSString stringWithFormat:@"张三%d", i], @"age":@20}];
            for (int j = 0; j < 2; j ++) {
                Book *book = [[Book alloc] initWithValue:@[[NSString stringWithFormat:@"红楼梦%d", j], @19.8, stu]];
                [[RLMRealm defaultRealm] transactionWithBlock:^{
                    [stu.books addObject:book];
                } error:nil];
            }
            
            [[RLMRealm defaultRealm] transactionWithBlock:^{
                [[RLMRealm defaultRealm] addObject:stu];
            } error:nil];
        }
        NSLog(@"save end");
    }
    
    - (IBAction)read:(id)sender {
        
        RLMResults *results = [Student allObjects];
        for (int i = 0; i < 50; i++) {
            Student *stu = results[i];
            NSLog(@"%@", stu.name);
        }
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    总结

    这篇文章主要说了一些比较浅的知识, 包括一些数据库的迁移这里也没有提到,如果有很多小伙伴想了解迁移的过程,后续楼主会写一篇关于迁移的文章。文中对CoreData的基本使用做了简单的介绍和使用, 但是没有对推荐库MR做简单的使用,同样的也只对SQLite常用的API做了简单的使用, 没有对FMDB进行使用, 我想大家应该对这两个库都有所了解,就没有进行介绍;Realm是2014年推出来的,当时这个库有很多的坑, 但是经过两年的发展,这个库也越来越完善,用起来也挺方便的,如果有新项目的可以试一下这个库。

    如果文章对你有帮助就点一波喜欢吧!!!
    注:楼主没有贴完整的代码(因为代码写的烂),如果有需求,楼主后续加上。

    相关文章

      网友评论

      本文标题:CoreData,SQLite,Realm的认识和使用

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