一、概念
CoreData介紹
CoreData是蘋果在iOS5推出來用于數(shù)據(jù)持久化的API,相對(duì)于SQLite來說,CoreData省去了寫SQL語句的麻煩,大家都知道在Xcode里面寫SQL語句特別容易出錯(cuò),只要出錯(cuò)這個(gè)bug我們估計(jì)要找半天吧!CoreData提供數(shù)據(jù)--OC對(duì)象映射關(guān)系來實(shí)現(xiàn)數(shù)據(jù)和對(duì)象的管理,這樣就無需任何的SQL語句來操作數(shù)據(jù)庫。
SQLite介紹
SQLite也是一款輕量級(jí)的數(shù)據(jù)庫,而且還是世界上使用最多的數(shù)據(jù)庫引擎,而且是開源的(官網(wǎng))和跨平臺(tái)的,這個(gè)才是王道。
Realm
Realm是個(gè)比較新的產(chǎn)品,官網(wǎng)出來的時(shí)間也是在2014年,同時(shí)Realm也是跨平臺(tái)的移動(dòng)數(shù)據(jù)庫,不僅支持Android,iOS還支持macOS,Linux,ReactNative和Xamarin,而且官方的文檔給的特別的清楚,還有中文版的,Realm的處理速度上和CoreData、SQLite的速度并不差,但是他的復(fù)雜程度相對(duì)于CoreData和SQLite來說就更簡(jiǎn)單。官網(wǎng),文檔
二、CoreData(推薦庫:MagicalRecord)
核心類與結(jié)構(gòu)
NSManagedObjectContext(數(shù)據(jù)上下文)
- 對(duì)象管理上下文,負(fù)責(zé)數(shù)據(jù)的實(shí)際操作
- 用于數(shù)據(jù)的增、刪、查、改
NSPersistentStoreCoordinator(持久化存儲(chǔ)助理)
- 相當(dāng)于數(shù)據(jù)庫的連接器
- 用于設(shè)置存儲(chǔ)的方法和存儲(chǔ)的位置
NSManagedObjectModel(數(shù)據(jù)模型)
- 數(shù)據(jù)庫所有表格或數(shù)據(jù)結(jié)構(gòu),包含各實(shí)體的定義信息
- 作用:添加實(shí)體的屬性,建立屬性之間的關(guān)系
NSManagedObject(被管理的數(shù)據(jù)記錄)
- 數(shù)據(jù)庫中的表格記錄
NSEntityDescription(實(shí)體結(jié)構(gòu))
- 相當(dāng)于表格結(jié)構(gòu)
NSFetchRequest(數(shù)據(jù)請(qǐng)求)
- 相當(dāng)于查詢語句
CoreData結(jié)構(gòu)圖:

從上面的圖中我們可以看到CoreData有三個(gè)功能部分:
上面的部分NSManagedObjectContext是管理的模型部分,由NSManagedObjectContext管理NSManagedObject,下面的部分是NSPersistentStore是負(fù)責(zé)實(shí)現(xiàn)本地持久化的部分,負(fù)責(zé)和SQL數(shù)據(jù)庫交互,中間的NSPersistentStoreCoordinator調(diào)度器作用是NSManagedObjectContext上部分存儲(chǔ)的數(shù)據(jù)交給中間的調(diào)度器NSPersistentStoreCoordinator,由調(diào)度器用具體的持久化對(duì)象NSPersistentStore來操作對(duì)應(yīng)的數(shù)據(jù)庫文件。
實(shí)現(xiàn)過程:
1.創(chuàng)建工程(本文不用這種方式,因?yàn)榭赡苣愕某绦驅(qū)懙揭话肓?,才想用CoreData,或者舊的項(xiàng)目沒有用CoreData,這時(shí)候再創(chuàng)建新工程,copy代碼,不敢往下想會(huì)浪費(fèi)多少時(shí)間...):
創(chuàng)建工程時(shí),會(huì)有一個(gè)勾選Use Core Data的選項(xiàng),如果你勾選了這個(gè)選項(xiàng),會(huì)在你的項(xiàng)目里自動(dòng)生成一些文件、對(duì)象和方法:

- 生成的文件是一個(gè)和項(xiàng)目同名的.xcdatamodeld的模型文件,在這里可以創(chuàng)建實(shí)體,再根據(jù)創(chuàng)建的實(shí)體創(chuàng)建模型對(duì)象。

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;
//數(shù)據(jù)的上下文
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
//數(shù)據(jù)模型
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
//持久化存儲(chǔ)助理
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
//保存當(dāng)前上下文中的數(shù)據(jù)
- (void)saveContext;
//數(shù)據(jù)庫的存儲(chǔ)位置
- (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.創(chuàng)建工程
- 創(chuàng)建和上面只是不勾選Use Core Data點(diǎn)擊創(chuàng)建
- command+N創(chuàng)建新文件iOS->Core Data->Data Model->Next,這一步創(chuàng)建的文件相當(dāng)于勾選Use Core Data自動(dòng)創(chuàng)建的.xcdatamodeld文件。

3.創(chuàng)建后的項(xiàng)目目錄

4.創(chuàng)建實(shí)體(Entity)
點(diǎn)擊上面創(chuàng)建的DataModel.xcdatamodeld文件,進(jìn)入可視化創(chuàng)建實(shí)體界面

5.添加關(guān)系
我在該實(shí)體中添加了兩個(gè)實(shí)體, 一個(gè)學(xué)生實(shí)體Student和一個(gè)書本實(shí)體Book,添加關(guān)系:
Student實(shí)體關(guān)系添加步驟詳圖:

Book實(shí)體添加關(guān)系步驟和上面基本相同,注意以下的紅圈:

上面完成后,你點(diǎn)擊Student類在student的最后選項(xiàng)inverse就會(huì)有值books,你點(diǎn)擊右下角的style可以看到兩個(gè)實(shí)體的關(guān)系如下圖:

6.創(chuàng)建對(duì)象類文件
command+N創(chuàng)建新文件iOS->Core Data-> NSManagedObject subclass ->Next -> Select Data Model ->Next -> Selcet Entity -> Next -> Create, 創(chuàng)建后的工程目錄

7.點(diǎn)擊Student+CoreDataProperties.h文件里面有屬性和方法,但是這里面的方法全部都沒有實(shí)現(xiàn),根據(jù)這些函數(shù)的命名大家應(yīng)該都知道什么意思, 而且這些函數(shù)的生成和圖7中To Many下面的Ordered的勾選有關(guān)系, 如果不勾選不會(huì)有那么多的函數(shù),而且這個(gè)里面books用的是NSOrderedSet,保證唯一性和一對(duì)多的關(guān)系
#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的處理(其實(shí)可以是用單例處理,這里我就不用了,有興趣的同學(xué)可以試一下)
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
//數(shù)據(jù)的上下文
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
//數(shù)據(jù)模型
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
//持久化存儲(chǔ)助理
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
//保存當(dāng)前上下文中的數(shù)據(jù)
- (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條數(shù)據(jù),和讀取10000條數(shù)據(jù).
//
// 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];
//創(chuàng)建學(xué)生對(duì)象
Student *stu = [[Student alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
stu.name = [NSString stringWithFormat:@"張三%d", i];
NSEntityDescription *bEntity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:context];
//創(chuàng)建Book對(duì)象
Book *book = [[Book alloc] initWithEntity:bEntity insertIntoManagedObjectContext:context];
book.title = @"紅樓夢(mèng)";
//添加Book對(duì)象
[stu addBooksObject:book];
//保存Student對(duì)象
[_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的時(shí)候不僅要導(dǎo)入頭文件sqlite3.h還要在Build Phases中引入庫libsqlite3.tdb(注意不是3.0)
常用的API(C語言的函數(shù))
//打開數(shù)據(jù)庫
int sqlite3_open(
const char *filename, /* 數(shù)據(jù)庫的路徑(UTF-8編碼) */
sqlite3 **ppDb /* 數(shù)據(jù)庫地址*/
);
//關(guān)閉數(shù)據(jù)庫
int sqlite3_close(sqlite3*) /*數(shù)據(jù)庫*/
//執(zhí)行數(shù)SQL語句
int sqlite3_exec(
sqlite3*, /* 一個(gè)打開的數(shù)據(jù)庫 */
const char *sql, /* SQL語句 */
int (*callback)(void*,int,char**,char**), /* 回調(diào)函數(shù) */
void *, /* 回調(diào)函數(shù)的第一個(gè)參數(shù) */
char **errmsg /* 錯(cuò)誤信息 */
);
//執(zhí)行SQL語句,將結(jié)果存在stmt中
int sqlite3_prepare_v2(
sqlite3 *db, /* 數(shù)據(jù)庫指針 */
const char *zSql, /* SQL語句 */
int nByte, /*長度, -1代表不限制 */
sqlite3_stmt **ppStmt, /* 執(zhí)行SQL語句后的結(jié)果集 */
const char **pzTail /* NULL */
);
//用于遍歷查詢結(jié)果
int sqlite3_step(
sqlite3_stmt* /*結(jié)果集*/
)
//取結(jié)果集的列數(shù)
int sqlite3_column_count(
sqlite3_stmt *pStmt /*結(jié)果集*/
);
//去結(jié)果集的列名
const char * sqlite3_column_name(
sqlite3_stmt*, /*結(jié)果集*/
int N /*第幾列*/
)
//取某一列的值,后面的text根據(jù)存儲(chǔ)的類型變化,可以是int, double等
const unsigned char *sqlite3_column_text(
sqlite3_stmt*, /*結(jié)果集*/
int iCol /*第幾列*/
);
對(duì)SQLite進(jìn)行簡(jiǎn)單的封裝(使用了單例)
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;
//打開數(shù)據(jù)庫
- (BOOL)openDataBaseWithName:(NSString *)name;
//關(guān)閉數(shù)據(jù)庫
- (BOOL)closeDB;
/**
* 創(chuàng)建表
*
* @param name 表名
*
* @return 創(chuàng)建是否成功
*/
- (BOOL)createTableWithName:(NSString *)name;
/**
* 插入數(shù)據(jù)
*
* @param sql sql語句
*
* @return 是否插入成功
*/
- (BOOL)insertDataWithSQL:(NSString *)sql;
/**
* 刪除數(shù)據(jù)
*
* @param sql SQL語句
*
* @return 是否刪除成功
*/
- (BOOL)deleteDataWithSQL:(NSString *)sql;
/**
* 更新數(shù)據(jù)
*
* @param sql SQL語句
*
* @return 是否更新成功
*/
- (BOOL)updataDataWithSQL:(NSString *)sql;
/**
* 查詢數(shù)據(jù)
*
* @param sql SQL語句
*
* @return 查詢結(jié)果
*/
- (NSArray *)selectDataWithSQL:(NSString *)sql;
/**
* 查詢數(shù)據(jù)
*
* @param sql SQL語句
*
* @return 是否有數(shù)據(jù)
*/
- (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]) {
// 創(chuàng)建一個(gè)數(shù)據(jù)庫的替身, 存儲(chǔ)對(duì)數(shù)據(jù)庫的所有操作
sqlite3_stmt *stmt = nil;
int result = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
if (SQLITE_OK == result) {
// 創(chuàng)建一個(gè)可變數(shù)組, 用于存儲(chǔ)數(shù)據(jù)
NSMutableArray *rows=[NSMutableArray array];
// 當(dāng)sql執(zhí)行成功, 遍歷數(shù)據(jù)
// 循環(huán)遍歷所有的結(jié)果, 每次遍歷到一條數(shù)據(jù), 都會(huì)返回sqlite_row, 如果沒有數(shù)據(jù)了, 就不會(huì)返回SQLITE_ROW, 跳出循環(huán)
while (SQLITE_ROW == sqlite3_step(stmt)) {
// 取int類型的數(shù)據(jù)
int columnCount = sqlite3_column_count(stmt);
// 創(chuàng)建一個(gè)可變字典, 用來存儲(chǔ)數(shù)據(jù)
NSMutableDictionary *dic=[NSMutableDictionary dictionary];
for (int i = 0; i < columnCount; i++) {
// 在循環(huán)體中去按列取數(shù)據(jù)
// 取得列名
const char *name = sqlite3_column_name(stmt, i);
// 取得某列的值
const unsigned char *value = sqlite3_column_text(stmt, i);
// 將char *字符串轉(zhuǎn)為NSString字符串
dic [[NSString stringWithUTF8String:name]] = [NSString stringWithUTF8String:(const char *) value];
}
[rows addObject:dic];
}
// 銷毀stmt替身, 把里面的操作和結(jié)果寫入本地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)
導(dǎo)入靜態(tài)庫
- 下載 Realm 的最新版本并解壓;
- 將 Realm.framework從 ios/static/文件夾拖曳到您 Xcode 項(xiàng)目中的文件導(dǎo)航器當(dāng)中。確保 Copy items if needed 選中然后單擊 Finish;
- 在 Xcode 文件導(dǎo)航器中選擇您的項(xiàng)目,然后選擇您的應(yīng)用目標(biāo),進(jìn)入到** Build Phases** 選項(xiàng)卡中。在 Link Binary with Libraries 中單擊 + 號(hào)然后添加 libc++.tbd和libz.tbd;
Realm的使用
- 創(chuàng)建數(shù)據(jù)庫的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;
- 增加數(shù)據(jù)模型類
創(chuàng)建Student類和Book類, 繼承自RLMObject。
Realm忽略了Objective-C的property attributes(如nonatomic, atomic, strong, copy, weak 等等)。 所以,推薦在創(chuàng)建模型的時(shí)候不要使用任何的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; //這里表示一對(duì)多的關(guān)系
@end
RLM_ARRAY_TYPE(Student) //宏定義 定義RLMArray<Student>這個(gè)類型
Student.m
//
// Student.m
// RealmTest
//
// Created by vcyber on 16/10/25.
// Copyright ? 2016年 vcyber. All rights reserved.
//
#import "Student.h"
@implementation Student
//設(shè)置主鍵
+ (NSString *)primaryKey {
return @"num";
}
//非空字段
+ (NSArray<NSString *> *)requiredProperties {
return @[@"name"];
}
//設(shè)置默認(rèn)值
+ (NSDictionary *)defaultPropertyValues {
return nil;
}
//設(shè)置忽略字段 如果設(shè)置該字段將不會(huì)插入數(shù)據(jù)庫
+ (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; //這里表示一對(duì)多的關(guān)系
@end
RLM_ARRAY_TYPE(Book) //宏定義 定義RLMArray<Book>這個(gè)類型
Book.m
//
// Book.m
// RealmTest
//
// Created by vcyber on 16/10/25.
// Copyright ? 2016年 vcyber. All rights reserved.
//
#import "Book.h"
@implementation Book
//設(shè)置默認(rèn)值
+ (NSDictionary *)defaultPropertyValues {
return nil;
}
//非空字段
+ (NSArray<NSString *> *)requiredProperties {
return @[@"title"];
}
//設(shè)置忽略字段 如果設(shè)置該字段將不會(huì)插入數(shù)據(jù)庫
+ (NSArray<NSString *> *)ignoredProperties {
return nil;
}
@end
- 初始化模型數(shù)據(jù)的方法
/**
* 初始化模型對(duì)象
*
* @param value 可以是字典,數(shù)組, 但是字段一定要對(duì)應(yīng)
*
* @return 模型對(duì)象
*/
- (instancetype)initWithValue:(id)value
/**
* 在默認(rèn)的數(shù)據(jù)庫中初始化模型對(duì)象
*
* @param value 字典或數(shù)組, 但是字段要對(duì)應(yīng)
*
* @return 模型對(duì)象
*/
+ (instancetype)createInDefaultRealmWithValue:(id)value;
/**
* 初始化模型對(duì)象
*
* @param realm 對(duì)應(yīng)的數(shù)據(jù)庫
* @param value 字典或數(shù)組
*
* @return 模型對(duì)象
*/
+ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value
/**
* 創(chuàng)建或者更新默認(rèn)數(shù)據(jù)庫中的數(shù)據(jù), 只有定義主鍵的數(shù)據(jù)模型才可以調(diào)用
*
* @param value 字典或數(shù)組
*
* @return 模型對(duì)象
*/
+ (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value;
/**
* 創(chuàng)建或者更新對(duì)應(yīng)數(shù)數(shù)據(jù)庫中的數(shù)據(jù), 只有定義主鍵的數(shù)據(jù)模型才可以調(diào)用
*
* @param realm 對(duì)應(yīng)的數(shù)據(jù)庫
* @param value 字典或數(shù)組
*
* @return 模型對(duì)象
*/
+ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value;
- 增、刪、查、改
1.事務(wù)中完成(增、刪、改應(yīng)該在事務(wù)開始和提交之間完成或者在block中完成)
//開始事務(wù)
- (void)beginWriteTransaction;
//提交事務(wù)
- (void)commitWriteTransaction NS_SWIFT_UNAVAILABLE("");
//帶有返回值的提交事務(wù)
- (BOOL)commitWriteTransaction:(NSError **)error;
//取消事務(wù)
- (void)cancelWriteTransaction;
//帶有block的事務(wù)提交
- (void)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block NS_SWIFT_UNAVAILABLE("");
//帶有block和返回值的事務(wù)提交
- (BOOL)transactionWithBlock:(__attribute__((noescape)) void(^)(void))block error:(NSError **)error;
2.增、改(由RLMRealm對(duì)象完成)
/**
添加一條數(shù)據(jù)到Realm中
*/
- (void)addObject:(RLMObject *)object;
/**
添加集合中的數(shù)據(jù)到Realm中 array是`NSArray` or `RLMResults`
*/
- (void)addObjects:(id<NSFastEnumeration>)array;
/**
添加或者更新已有的某條數(shù)據(jù)
*/
- (void)addOrUpdateObject:(RLMObject *)object;
/**
添加或者更新已有的集合中的數(shù)據(jù) array是`NSArray` or `RLMResults`
*/
- (void)addOrUpdateObjectsFromArray:(id)array;
3.刪(由RLMRealm對(duì)象完成)
/**
刪除一條數(shù)據(jù)
*/
- (void)deleteObject:(RLMObject *)object;
/**
刪除一個(gè)或多個(gè)數(shù)據(jù)
@param array An `RLMArray`, `NSArray`, or `RLMResults` of `RLMObject`s (or subclasses) .
*/
- (void)deleteObjects:(id)array;
/**
刪除所有的數(shù)據(jù)
*/
- (void)deleteAllObjects;
4.查(由對(duì)應(yīng)的模型類完成)
#pragma mark -在默認(rèn)數(shù)據(jù)庫中的查詢
/**
返回默認(rèn)數(shù)據(jù)庫所有的數(shù)據(jù)
*/
+ (RLMResults *)allObjects;
/**
條件查詢
*/
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ...;
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args;
+ (RLMResults *)objectsWithPredicate:(nullable NSPredicate *)predicate;
#pragma mark - 查詢某一個(gè)數(shù)據(jù)庫
/**
查詢所有數(shù)據(jù)
*/
+ (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:@"紅樓夢(mèng)%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
總結(jié)
這篇文章主要說了一些比較淺的知識(shí), 包括一些數(shù)據(jù)庫的遷移這里也沒有提到,如果有很多小伙伴想了解遷移的過程,后續(xù)樓主會(huì)寫一篇關(guān)于遷移的文章。文中對(duì)CoreData的基本使用做了簡(jiǎn)單的介紹和使用, 但是沒有對(duì)推薦庫MR做簡(jiǎn)單的使用,同樣的也只對(duì)SQLite常用的API做了簡(jiǎn)單的使用, 沒有對(duì)FMDB進(jìn)行使用, 我想大家應(yīng)該對(duì)這兩個(gè)庫都有所了解,就沒有進(jìn)行介紹;Realm是2014年推出來的,當(dāng)時(shí)這個(gè)庫有很多的坑, 但是經(jīng)過兩年的發(fā)展,這個(gè)庫也越來越完善,用起來也挺方便的,如果有新項(xiàng)目的可以試一下這個(gè)庫。
如果文章對(duì)你有幫助就點(diǎn)一波喜歡吧?。?!
注:樓主沒有貼完整的代碼(因?yàn)榇a寫的爛),如果有需求,樓主后續(xù)加上。