CoreData,SQLite,Realm的認識和使用

一、概念

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年推出來的,當時這個庫有很多的坑, 但是經過兩年的發展,這個庫也越來越完善,用起來也挺方便的,如果有新項目的可以試一下這個庫。

如果文章對你有幫助就點一波喜歡吧!!!
注:樓主沒有貼完整的代碼(因為代碼寫的爛),如果有需求,樓主后續加上。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容