博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据存储
阅读量:5755 次
发布时间:2019-06-18

本文共 23597 字,大约阅读时间需要 78 分钟。

分析数据存储方式,我们首先从底层的实现去分析,然后往上看。首先,我们来看一下如何使用SQLite去操作数据库。

SQLite

DBManager.h
#import 
@interface StorageItem : NSObject@property (nonatomic, strong) NSString *key;@property (nonatomic, strong) NSData *value;@property (nullable, nonatomic, strong) NSString *filename;@property (nonatomic) int size;@property (nonatomic) int modTime;@property (nonatomic) int accessTime;@property (nullable, nonatomic, strong) NSData *extendedData; @end@interface DBManager : NSObject- (instancetype)initWithPath:(NSString *)path;@end复制代码
DBManager.c
#import "DBManager.h"#import 
#import
static const NSUInteger kMaxErrorRetryCount = 8;static const NSTimeInterval kMinRetryTimeInterval = 2.0;static const int kPathLengthMax = PATH_MAX - 64;static NSString *const kDBFileName = @"manifest.sqlite";static NSString *const kDBShmFileName = @"manifest.sqlite-shm";static NSString *const kDBWalFileName = @"manifest.sqlite-wal";@implementation StorageItem@end@implementation DBManager { NSString *_dbPath; sqlite3 *_db; CFMutableDictionaryRef _dbStmtCache; NSTimeInterval _dbLastOpenErrorTime; NSUInteger _dbOpenErrorCount;}-(instancetype)initWithPath:(NSString *)path { if (path.length == 0 || path.length > kPathLengthMax) { NSLog(@"DBManager init error: invalid path:[%@].", path); return nil; } self = [super init]; _dbPath = [path stringByAppendingString:kDBFileName]; if (![self _dbOpen] || ![self _dbInitialize]) { [self _dbClose]; if (![self _dbOpen] || ![self _dbInitialize]) { [self _dbClose]; NSLog(@"DBManager init error: fail to open sqlite db."); return nil; } } return self;}#pragma mark - db- (BOOL)_dbOpen { if (_db) return YES; int result = sqlite3_open(_dbPath.UTF8String, &_db); if (result == SQLITE_OK) { CFDictionaryKeyCallBacks keyCallBacks = kCFTypeDictionaryKeyCallBacks; CFDictionaryValueCallBacks valueCallBacks = {
0}; _dbStmtCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &keyCallBacks, &valueCallBacks); _dbLastOpenErrorTime = 0; _dbOpenErrorCount = 0; return YES; } else { _db = NULL; if (_dbStmtCache) CFRelease(_dbStmtCache); _dbStmtCache = NULL; _dbLastOpenErrorTime = CACurrentMediaTime(); _dbOpenErrorCount++; NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result); return NO; }}- (BOOL)_dbClose { if (_db) return YES; int result = 0; BOOL retry = NO; BOOL stmtFinalized = NO; if (_dbStmtCache) CFRelease(_dbStmtCache); _dbStmtCache = NULL; do { retry = NO; result = sqlite3_close(_db); if (result == SQLITE_BUSY || result == SQLITE_LOCKED) { if (!stmtFinalized) { stmtFinalized = YES; sqlite3_stmt *stmt; while ((stmt = sqlite3_next_stmt(_db, nil)) != 0) { sqlite3_finalize(stmt); retry = YES; } } } else if (result != SQLITE_OK) { NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result); } } while (retry); _db = NULL; return YES;}- (BOOL)_dbCheck { if (!_db) { if (_dbOpenErrorCount < kMaxErrorRetryCount && CACurrentMediaTime() - _dbLastOpenErrorTime > kMinRetryTimeInterval) { return [self _dbOpen] && [self _dbInitialize]; } else { return NO; } } return YES;}- (BOOL)_dbInitialize { NSString *sql = @"pragma journal_mode = wal; pragma synchronous = normal; create table if not exists mainfest (key text, filename text, size integer, inline_data blob, modification_time integer, last_access_time integer, extended_data blob, primary key(key)); create index if not exists last_access_time_idx on mainfest(last_access_time);"; return [self _dbExecute:sql];}- (BOOL)_dbExecute:(NSString *)sql { if (sql.length == 0) return NO; if (![self _dbCheck]) return NO; char *error = NULL; int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error); if (error) { NSLog(@"%s line:%d sqlite exec error (%d): %s", __FUNCTION__, __LINE__, result, error); sqlite3_free(error); } return result == SQLITE_OK;}- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql { if (![self _dbCheck] || sql.length == 0 || !_dbStmtCache) return NULL; sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql)); if (!stmt) { int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL); if (result != SQLITE_OK) { NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NULL; } CFDictionarySetValue(_dbStmtCache, (__bridge const void *)(sql), stmt); } else { sqlite3_reset(stmt); } return stmt;}- (NSString *)_dbJoinedKeys:(NSArray *)keys { NSMutableString *string = [NSMutableString new]; for (NSUInteger i = 0, max = keys.count; i < max; i++) { [string appendString:@"?"]; if (i + 1 != max) { [string appendString:@","]; } } return string;}- (void)_dbBindJoinedKeys:(NSArray *)keys stmt:(sqlite3_stmt *)stmt fromIndex:(int)index { for (int i = 0, max = (int)keys.count; i < max; i++) { NSString *key = keys[i]; sqlite3_bind_text(stmt, index + i, key.UTF8String, -1, NULL); }}- (BOOL)_dbSaveWithKey:(NSString *)key value:(NSData *)value fileName:(NSString *)fileName extendedData:(NSData *)extendedData { NSString *sql = @"insert or replace into mainfest (key, filename, size, inline_data, modification_time, last_access_time, extended_data) values (?1, ?2, ?3, ?4, ?5, ?6. ?7);"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return NO; int timestamp = (int)time(NULL); sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); sqlite3_bind_text(stmt, 2, fileName.UTF8String, -1, NULL); sqlite3_bind_int(stmt, 3, (int)value.length); if (fileName.length == 0) { sqlite3_bind_blob(stmt, 4, value.bytes, (int)value.length, 0); } else { sqlite3_bind_blob(stmt, 4, NULL, 0, 0); } sqlite3_bind_int(stmt, 5, timestamp); sqlite3_bind_int(stmt, 6, timestamp); sqlite3_bind_blob(stmt, 7, extendedData.bytes, (int)extendedData.length, 0); int result = sqlite3_step(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite insert error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbUpdateAccessTimeWithKey:(NSString *)key { NSString *sql = @"update mainfest set last_access_time = ?1 where key = ?2;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return NO; sqlite3_bind_int(stmt, 1, (int)time(NULL)); sqlite3_bind_text(stmt, 2, key.UTF8String, -1, NULL); sqlite3_bind_text(stmt, 2, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite update error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbUpdateAccessTimeWithKeys:(NSArray *)keys { if (![self _dbCheck]) return NO; int t = (int)time(NULL); NSString *sql = [NSString stringWithFormat:@"update mainfest set last_access_time = %d where key in (%@);", t, [self _dbJoinedKeys:keys]]; sqlite3_stmt *stmt = NULL; int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL); if (result != SQLITE_OK) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1]; result = sqlite3_step(stmt); sqlite3_finalize(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbDeleteItemWithKey:(NSString *)key { NSString *sql = @"delete from mainfest where key = ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return NO; sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbDeleteItemWithKeys:(NSArray *)keys { if (![self _dbCheck]) return NO; NSString *sql = [NSString stringWithFormat:@"delete from mainfest where key in (%@);", [self _dbJoinedKeys:keys]]; sqlite3_stmt *stmt = NULL; int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL); if (result != SQLITE_OK) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1]; result = sqlite3_step(stmt); sqlite3_finalize(stmt); if (result == SQLITE_ERROR) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbDeleteItemsWithSizeLargerThan:(int)size { NSString *sql = @"delete from mainfest where size > ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return NO; sqlite3_bind_int(stmt, 1, size); int result = sqlite3_step(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (BOOL)_dbDeleteItemsWithTimerEarlierThan:(int)time { NSString *sql = @"delete from mainfest where last_access_time < ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return NO; sqlite3_bind_int(stmt, 1, time); int result = sqlite3_step(stmt); if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return NO; } return YES;}- (StorageItem *)_dbGetItemFromStmt:(sqlite3_stmt *)stmt exculdeInlineData:(BOOL)exculdeInlineData { int i = 0; char *key = (char *)sqlite3_column_text(stmt, i++); char *fileName = (char *)sqlite3_column_text(stmt, i++); int size = sqlite3_column_int(stmt, i++); const void *inline_data = exculdeInlineData ? NULL : sqlite3_column_blob(stmt, i); int inline_data_bytes = exculdeInlineData ? 0 : sqlite3_column_bytes(stmt, i++); int modification_time = sqlite3_column_int(stmt, i++); int last_access_time = sqlite3_column_int(stmt, i++); const void *extended_data = sqlite3_column_blob(stmt, i); int extended_data_bytes = sqlite3_column_bytes(stmt, i++); StorageItem *item = [StorageItem new]; if (key) item.key = [NSString stringWithUTF8String:key]; if (fileName && *fileName != 0) item.filename = [NSString stringWithUTF8String:fileName]; item.size = size; if (inline_data_bytes > 0 && inline_data) item.value = [NSData dataWithBytes:inline_data length:inline_data_bytes]; item.modTime = modification_time; item.accessTime = last_access_time; if (extended_data_bytes > 0 && extended_data) item.extendedData = [NSData dataWithBytes:extended_data length:extended_data_bytes]; return item;}- (StorageItem *)_dbGetItemWithKey:(NSString *)key exculdeInlineData:(BOOL)exculdeInlineData { NSString *sql = exculdeInlineData ? @"select key, filename, size, modification_time, last_access_time, extended_data from mainfest where key = ?1;" : @"select key, filename, size, inline_data, modification_time, last_access_time, extended_data from mainfest where key = ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return nil; sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); StorageItem *item = nil; int result = sqlite3_step(stmt); if (result == SQLITE_ROW) { item = [self _dbGetItemFromStmt:stmt exculdeInlineData:exculdeInlineData]; } else { if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } } return item;}- (NSData *)_dbGetValueWithKey:(NSString *)key { NSString *sql = @"select inline_data from mainfest where key = ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return nil; sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); if (result == SQLITE_ROW) { const void *inline_data = sqlite3_column_blob(stmt, 0); int inline_data_bytes = sqlite3_column_bytes(stmt, 0); if (!inline_data || inline_data_bytes <= 0) return nil; return [NSData dataWithBytes:inline_data length:inline_data_bytes]; } else { if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } return nil; }}- (NSString *)_dbGetFileNameWithKey:(NSString *)key { NSString *sql = @"select filename from mainfest where key = ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return nil; sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL); int result = sqlite3_step(stmt); if (result == SQLITE_ROW) { char *filename = (char *)sqlite3_column_text(stmt, 0); if (filename && *filename != 0) { return [NSString stringWithUTF8String:filename]; } else { if (result != SQLITE_DONE) { NSLog(@"%s line: %d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); } } } return nil;}- (NSMutableArray *)_dbGetFilenameWithKeys:(NSArray *)keys { if (![self _dbCheck]) return nil; NSString *sql = [NSString stringWithFormat:@"select filename from mainfest where key in (%@);", [self _dbJoinedKeys:keys]]; sqlite3_stmt *stmt = NULL; int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL); if (result != SQLITE_OK) { NSLog(@"%s line:%d sqlite stmt prepare error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); return nil; } [self _dbBindJoinedKeys:keys stmt:stmt fromIndex:1]; NSMutableArray *filenames = [NSMutableArray new]; do { result = sqlite3_step(stmt); if (result == SQLITE_ROW) { char *filename = (char *)sqlite3_column_text(stmt, 0); if (filename && *filename != 0) { NSString *name = [NSString stringWithUTF8String:filename]; if (name) [filenames addObject:name]; } } else if (result == SQLITE_DONE) { break; } else { NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); filenames = nil; break; } } while (1); sqlite3_finalize(stmt); return filenames;}- (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeAscWithLimit:(int)count { NSString *sql = @"select key, filename, size from mainfest order by last_access_time asc limit ?1;"; sqlite3_stmt *stmt = [self _dbPrepareStmt:sql]; if (!stmt) return nil; sqlite3_bind_int(stmt, 1, count); NSMutableArray *items = [NSMutableArray new]; do { int result = sqlite3_step(stmt); if (result == SQLITE_ROW) { char *key = (char *)sqlite3_column_text(stmt, 0); char *filename = (char *)sqlite3_column_text(stmt, 1); int size = sqlite3_column_int(stmt, 2); NSString *keyStr = key ? [NSString stringWithUTF8String:key] : nil; if (keyStr) { StorageItem *item = [StorageItem new]; item.key = keyStr; item.filename = filename ? [NSString stringWithUTF8String:filename] : nil; item.size = size; [items addObject:item]; } } else if (result == SQLITE_DONE) { break; } else { NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db)); items = nil; break; } } while (1); return items;}@end复制代码

上述代码列举了sqlite的使用。sqlite在使用时格式固定。下面我们来分析一下:

  1. 导入头文件
#import 
复制代码
  1. 声明数据库连接句柄
// Database Connection Handlesqlite3 *_db;复制代码
  1. 打开数据库
int sqlite3_open(  const char *filename,   /* Database filename (UTF-8) */  sqlite3 **ppDb          /* OUT: SQLite db handle */);复制代码
  1. 创建表命令
NSString *sql = @"pragma journal_mode = wal; pragma synchronous = normal; create table if not exists mainfest (key text, filename text, size integer, inline_data blob, modification_time integer, last_access_time integer, extended_data blob, primary key(key)); create index if not exists last_access_time_idx on mainfest(last_access_time);";复制代码
  1. 执行SQL
int sqlite3_exec(  sqlite3*,                                  /* An open database */  const char *sql,                           /* SQL to be evaluated */  int (*callback)(void*,int,char**,char**),  /* Callback function */  void *,                                    /* 1st argument to callback */  char **errmsg                              /* Error msg written here */);复制代码
  1. 预编译
int sqlite3_prepare_v2(  sqlite3 *db,            /* Database handle */  const char *zSql,       /* SQL statement, UTF-8 encoded */  int nByte,              /* Maximum length of zSql in bytes. */  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */  const char **pzTail     /* OUT: Pointer to unused portion of zSql */);复制代码
  1. 数据绑定
int sqlite3_bind_null(sqlite3_stmt*, int);int sqlite3_bind_int(sqlite3_stmt*, int, int);int sqlite3_bind_double(sqlite3_stmt*, int, double);int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));复制代码
  1. 分步执行
// Evaluate An SQL Statementint sqlite3_step(sqlite3_stmt*);复制代码
  1. 取出数据
int sqlite3_column_int(sqlite3_stmt*, int iCol);double sqlite3_column_double(sqlite3_stmt*, int iCol);const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);int sqlite3_column_bytes(sqlite3_stmt*, int iCol);const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);复制代码
  1. 关闭数据库,置空数据库连接句柄
int sqlite3_close(sqlite3*);_db = NULL;复制代码

FMDB

看完上面密密麻麻的代码,估计很多人已经一个头两个大。作为开发者,我们要知道SQLite的使用,但是如果在代码中频繁的编写上述代码,还是很痛苦的。接下来我们来看一下第三方框架:FMDB。

首先还是来看一下FMDB中都有哪些类。

  1. FMDatabase.h
  2. FMResultSet.h
  3. FMDatabaseQueue.h
  4. FMDatabaseAdditions.h
  5. FMDatabasePool.h

我们来实际使用一下FMDB

#import 
#import
@class HotMovieModel;@interface FMDBShare : NSObject+ (instancetype)shareDataBase;- (NSString *)filePathWithFileName:(NSString *)fileName;- (BOOL)createTable;- (BOOL)insertInfoIntoTable:(HotMovieModel *)model;- (NSMutableArray *)selectFromTableWithId:(NSInteger)Id;- (NSMutableArray *)selectAllInfoFromTable;@end复制代码
#import "FMDBShare.h"#import "FMDatabase.h"#import "HotMovieModel.h"#define  HotMovie @"hotMovie.db"@interface FMDBShare ()@property (nonatomic, strong) FMDatabase *dbBase;@end@implementation FMDBShare+ (instancetype)shareDataBase {    static dispatch_once_t once;    static FMDBShare *share;        dispatch_once(&once, ^{        share = [[FMDBShare alloc] init];                if (![share.dbBase open]) {            NSLog(@"%@", [share.dbBase lastErrorMessage]);            return;        }                [share createTable];    });        return share;}- (NSString *)filePathWithFileName:(NSString *)fileName {    NSString *fileDirectory = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];    return [fileDirectory stringByAppendingPathComponent:fileName];}- (FMDatabase *)dbBase {    if (_dbBase) {        return _dbBase;    }        _dbBase = [FMDatabase databaseWithPath:[self filePathWithFileName:HotMovie]];    return _dbBase;}- (BOOL)createTable {        BOOL result = [self.dbBase executeUpdate:@"create table if not exists HotMovie(Id integer primary key, img text, nm text, mk float, showInfo text, scm text)"];        if (!result) {        NSLog(@"%@", [self.dbBase lastErrorMessage]);    }    return result;}- (BOOL)insertInfoIntoTable:(HotMovieModel *)model {    BOOL result = [self.dbBase executeUpdate:@"insert into HotMovie(Id, img, nm, mk, showInfo, scm) values (?,?,?,?,?,?)", @(model.Id), model.img, model.nm, @(model.mk), model.showInfo, model.scm];    if (!result) {        NSLog(@"%@", [self.dbBase lastErrorMessage]);    }        return result;}- (NSMutableArray *)selectFromTableWithId:(NSInteger)Id {    FMResultSet *set = [self.dbBase executeQuery:@"select * from HotMovie where Id=?", @(Id)];        while ([set next]) {        return [NSMutableArray arrayWithObject:[HotMovieModel modelWithDictionary:[set resultDictionary]]];    }        return nil;}- (NSMutableArray *)selectAllInfoFromTable {    FMResultSet *set = [self.dbBase executeQuery:@"select * from HotMovie"];        NSMutableArray *mArr = [NSMutableArray array];    while ([set next]) {        HotMovieModel *model = [HotMovieModel modelWithDictionary:[set resultDictionary]];        [mArr addObject:model];    }        return mArr;}@end复制代码

使用FMDB框架,我们就可以从繁琐的SQLite中解脱出来,专注于查询逻辑的设计。FMDB也帮我们集成了数据库的回滚操作。

CoreData

CoreData是苹果提供的数据库存储方案,以面向对象的方式去操作数据库。

从上图我们可以看到CoreData整体面貌,SQLite中的每张table表对应的是NSManagedObject,NSManagedObject存在于NSManagedObjectContext。我们通过context去执行数据的增删改查等。NSManagedObjectContext受NSPersistentStoreCoordinator管理。NSPersistentStoreCoordinator包含有NSPersistentStore,NSPersistentStore对应一个SQLite文件,SQLite文件存储于FileSystem下。

下面我们使用CoreData创建两张表:

我们可以切换表的显示形式,更直观的感受两者的关联。
执行下图所示操作,然后按照提示执行,Xcode会生成相应的文件

// 获取Context    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];    NSPersistentContainer *persistentContainer = appDelegate.persistentContainer;    NSManagedObjectContext *context = persistentContainer.viewContext;        // 新增数据    TB_Example *exampleModel = [NSEntityDescription insertNewObjectForEntityForName:@"TB_Example" inManagedObjectContext:context];    exampleModel.typeInt = 1;    exampleModel.typeString = @"String";    exampleModel.typeBool = YES;    exampleModel.typeDate = [NSDate date];    exampleModel.typeFloat = 1.0;    exampleModel.typeDouble = 1.0;    NSError *error = nil;    [context save:&error];        // 查询数据    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];    NSEntityDescription *entity = [NSEntityDescription entityForName:@"TB_Example" inManagedObjectContext:context];    [fetchRequest setEntity:entity];    // Specify criteria for filtering which objects to fetch    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"typeString=String"];    [fetchRequest setPredicate:predicate];    // Specify how the fetched objects should be sorted    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"typeInt" ascending:YES];    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];        NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];    if (fetchedObjects == nil) {//        Error handling code    }        // 修改数据    exampleModel.typeInt = 2;    exampleModel.typeString = @"newString";    [context save:&error];        // 删除数据    [context deleteObject:exampleModel];    [context save:&error];复制代码

参考源码:

转载于:https://juejin.im/post/5adfca756fb9a07a9d6ffcea

你可能感兴趣的文章
深克隆与序列化效率的比较
查看>>
lamp+nginx代理+discuz+wordpress+phpmyadmin搭建一
查看>>
nagios监控使用139邮箱报警
查看>>
Windows Phone 7 中各种Task解说(启动器与选择器)
查看>>
罗森伯格助力2011年中国智能建筑技术发展应用论坛哈尔滨站
查看>>
网络割接
查看>>
windows server 2016 活动目录(二)
查看>>
openstack G版 修改vm的flavor级别
查看>>
python_控制台输出带颜色的文字方法
查看>>
java泛型中特殊符号的含义
查看>>
一秒 解决 ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql 问题
查看>>
Android组件化最佳实践 ARetrofit原理
查看>>
舍弃浮躁, 50条重要的C++学习建议
查看>>
同步手绘板——将View的内容映射成Bitmap转图片导出
查看>>
【Android游戏开发之十】(优化处理)详细剖析Android Traceview 效率检视工具!分析程序运行速度!并讲解两种创建SDcard方式!...
查看>>
微信小程序之wx.navigateback往回携带参数
查看>>
陌陌和请吃饭之类的应用,你要是能玩转,那就厉害了
查看>>
递归的运行机制简单理解
查看>>
汉字转阿斯克马值
查看>>
Java 栈与堆简介
查看>>