1.xcode8 無法創建NSManagedObjectModel subClass和 創建NSManagedObjectModel subClass爲swift版本 問題解決見鏈接 點擊打開鏈接
2.FMDB和CoreData性能問題比較
1)經過樓主真機測試,大量數據插入(超過1萬條) FMDB經過僞批處理之後的性能和CoreData性能旗鼓相當,一萬條數據 500 ms左右。
解釋一下FMDB的僞批處理,因爲FMDB默認每條插入操作都當做一次事務處理,所以單純直接循環10000次插入操作,時間消耗非常之大,10000條數據約需三分鐘,如果採用統一開啓事務處理方式,FMDB自動取消每次插入的事務,處理速度大大加快,就是上述 10000條數據 500 ms左右。
僞批處理(統一事務處理)代碼如下:
//增加數據
- (void)addFMDB {
[self.db beginTransaction];
BOOL isRollBack = NO;
@try {
//往表中循環插入100條數據
for (int i = 0; i < 50000 ; i++) {
//名稱設置爲J_mailbox
NSString *name = [NSString stringWithFormat:@"J_mailbox-%d",i];
//隨機生成20歲~25歲之間的記錄
NSInteger age = arc4random_uniform(5) + 20;
//sql插入語句的拼接
NSString *resultStr = [NSString stringWithFormat:@"INSERT INTO t_test (NAME,AGE) VALUES('%@',%zd) ",name,age];
//執行sql插入語句(調用FMDB對象方法)
BOOL success = [self.db executeUpdate:resultStr];
//判斷是否添加成功
// if (success) {
// NSLog(@"添加數據成功!");
// }else{
// NSLog(@"添加數據失敗!");
// }
}
} @catch (NSException *exception) {
isRollBack = YES;
[self.db rollback];
} @finally {
if (!isRollBack) {
[self.db commit];
NSLog(@"最終成功");
}
}
}
2) 對於查詢操作,而且速度差不多,但對於批量刪除操作,批量更新操作,由於CoreData需要先查詢找到相應的實體對象然後再執行更新操作,效率低了很多。
3.完整FMDB和CoreData對比demo示例代碼如下
#import "ViewController.h"
#import <sqlite3.h>
#import "FMDB.h"
#import <CoreData/CoreData.h>
@interface ViewController ()
@property (strong,nonatomic) FMDatabase *db;
@property (strong,nonatomic) NSManagedObjectContext *coreDataContext;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initUI];
[self connectionDB];
[self initCoreData];
}
-(void)operetionClick:(UIButton *)btn
{
CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();
if (btn.tag < 4)
{
//fmdb
switch (btn.tag) {
case 0:
{
[self addFMDB];
}
break;
case 1:
{
[self deleteFMDB];
}
break;
case 2:
{
[self changeFMDB];
}
break;
case 3:
{
[self queryFMDB];
}
break;
default:
break;
}
} else {
//core Data
switch (btn.tag) {
case 4:
{
[self addCoreData];
}
break;
case 5:
{
[self deleteCoreData];
}
break;
case 6:
{
}
break;
case 7:
{
[self queryCoreData];
}
break;
default:
break;
}
}
CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
NSLog(@"Linked in %f ms", linkTime *1000.0);
}
- (void)initCoreData
{
// 從應用程序包中加載模型文件
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
// 傳入模型對象,初始化NSPersistentStoreCoordinator
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// 構建SQLite數據庫文件的路徑
NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *url = [NSURL fileURLWithPath:[docs stringByAppendingPathComponent:@"person.data"]];
NSLog(@"%@",url);
// 添加持久化存儲庫,這裏使用SQLite作爲存儲庫
NSError *error = nil;
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
if (store == nil) { // 直接拋異常
[NSException raise:@"添加數據庫錯誤" format:@"%@", [error localizedDescription]];
}
// 初始化上下文,設置persistentStoreCoordinator屬性
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = psc;
self.coreDataContext = context;
}
- (void)addCoreData
{
for (int i = 0; i < 10000; i++) {
NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.coreDataContext];
// 設置Person的簡單屬性
[person setValue:[NSString stringWithFormat:@"zss%d",i] forKey:@"name"];
[person setValue:[NSNumber numberWithInt:27] forKey:@"age"];
}
// 利用上下文對象,將數據同步到持久化存儲庫
NSError *error = nil;
BOOL success = [self.coreDataContext save:&error];
if (!success) {
[NSException raise:@"訪問數據庫錯誤" format:@"%@", [error localizedDescription]];
} else {
NSLog(@"全部添加成功");
}
}
- (void)queryCoreData
{
// 初始化一個查詢請求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 設置要查詢的實體
request.entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:self.coreDataContext];
// 設置排序(按照age降序)
// NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
// request.sortDescriptors = [NSArray arrayWithObject:sort];
// 設置條件過濾(搜索name中包含字符串"Itcast-1"的記錄,注意:設置條件過濾時,數據庫SQL語句中的%要用*來代替,所以%Itcast-1%應該寫成*Itcast-1*)
// NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@", @"*Itcast-1*"];
// request.predicate = predicate;
// 執行請求
NSError *error = nil;
NSArray *objs = [self.coreDataContext executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查詢錯誤" format:@"%@", [error localizedDescription]];
}
// 遍歷數據
for (NSManagedObject *obj in objs)
{
NSLog(@"name=%@", [obj valueForKey:@"name"]);
}
}
- (void)deleteCoreData
{
// 初始化一個查詢請求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 設置要查詢的實體
request.entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:self.coreDataContext];
NSError *error = nil;
NSArray *objs = [self.coreDataContext executeFetchRequest:request error:&error];
if (error) {
[NSException raise:@"查詢錯誤" format:@"%@", [error localizedDescription]];
}
// 遍歷數據
for (NSManagedObject *obj in objs)
{
// 傳入需要刪除的實體對象
[self.coreDataContext deleteObject:obj];
}
// 將結果同步到數據庫
error = nil;
[self.coreDataContext save:&error];
if (error) {
[NSException raise:@"刪除錯誤" format:@"%@", [error localizedDescription]];
} else {
NSLog(@"全部刪除成功");
}
}
//連接數據庫
- (void)connectionDB{
//創建數據庫路徑
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"data.sqlite"];
NSLog(@"%@",path);
FMDatabase *db = [FMDatabase databaseWithPath:path];
self.db = db;
BOOL success = [db open];
if (success) { //打開成功
NSLog(@"數據庫創建成功!");
//創建表 執行一條sql語句 增刪改 都是這樣的 查詢比較特殊
NSString *sqlStr = @"CREATE TABLE IF NOT EXISTS t_test (ID INTEGER PRIMARY KEY AUTOINCREMENT ,NAME TEXT ,AGE INTEGER );";
BOOL successT = [self.db executeUpdate:sqlStr];
if (successT) {
NSLog(@"創建表成功!");
}else{
NSLog(@"創建表失敗!");
}
}else{
NSLog(@"數據庫創建失敗!");
}
NSLog(@"%@",NSHomeDirectory());
//關閉數據庫
//sqlite3_close(_db);
}
//增加數據
- (void)addFMDB {
[self.db beginTransaction];
BOOL isRollBack = NO;
@try {
//往表中循環插入100條數據
for (int i = 0; i < 50000 ; i++) {
//名稱設置爲J_mailbox
NSString *name = [NSString stringWithFormat:@"J_mailbox-%d",i];
//隨機生成20歲~25歲之間的記錄
NSInteger age = arc4random_uniform(5) + 20;
//sql插入語句的拼接
NSString *resultStr = [NSString stringWithFormat:@"INSERT INTO t_test (NAME,AGE) VALUES('%@',%zd) ",name,age];
//執行sql插入語句(調用FMDB對象方法)
BOOL success = [self.db executeUpdate:resultStr];
//判斷是否添加成功
// if (success) {
// NSLog(@"添加數據成功!");
// }else{
// NSLog(@"添加數據失敗!");
// }
}
} @catch (NSException *exception) {
isRollBack = YES;
[self.db rollback];
} @finally {
if (!isRollBack) {
[self.db commit];
NSLog(@"最終成功");
}
}
}
//刪除數據
- (void)deleteFMDB {
//刪除語句
NSString *sqlStr = @"DELETE FROM t_test WHERE AGE > 19 ;";
//執行sql刪除語句(調用FMDB對象方法)
BOOL success = [self.db executeUpdate:sqlStr];
if (success) {
NSLog(@"刪除數據成功!");
}else{
NSLog(@"刪除數據失敗!");
}
}
//修改數據
- (void)changeFMDB{
//修改語句
NSString *sqlStr = @"UPDATE t_test SET AGE = 30 WHERE AGE > 19;";
//執行sql修改語句(調用FMDB對象方法)
BOOL success = [self.db executeUpdate:sqlStr];
if (success) {
NSLog(@"修改數據成功!");
}else{
NSLog(@"修改數據失敗!");
}
}
//查詢數據
- (void)queryFMDB {
//查詢語句
NSString *sqlStr = @"SELECT NAME,AGE FROM t_test WHERE AGE > 19;";
//執行sql查詢語句(調用FMDB對象方法)
FMResultSet *set = [self.db executeQuery:sqlStr];
while ([set next]) { //等價於 == sqlite_Row
//NAME
NSString *name = [set stringForColumnIndex:0];
//AGE
NSInteger age = [set intForColumnIndex:1];
NSLog(@"NAME = %@ AGE = %ld",name,(long)age);
}
}
- (void)initUI
{
CGFloat x = 50,y = 50;
UILabel *fmdbLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
fmdbLabel.text = @"fmdb";
[fmdbLabel sizeToFit];
[self.view addSubview:fmdbLabel];
x -= 5;
y += 50;
UIButton *addBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[addBtn setTitle:@"add" forState:UIControlStateNormal];
[addBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
addBtn.tag = 0;
[addBtn addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[addBtn sizeToFit];
[self.view addSubview:addBtn];
y += 50;
UIButton *deleteBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[deleteBtn setTitle:@"delete" forState:UIControlStateNormal];
[deleteBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
deleteBtn.tag = 1;
[deleteBtn addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[deleteBtn sizeToFit];
[self.view addSubview:deleteBtn];
y += 50;
UIButton *changeBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[changeBtn setTitle:@"change" forState:UIControlStateNormal];
[changeBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
changeBtn.tag = 2;
[changeBtn addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[changeBtn sizeToFit];
[self.view addSubview:changeBtn];
y += 50;
UIButton *queryBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[queryBtn setTitle:@"query" forState:UIControlStateNormal];
[queryBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
queryBtn.tag = 3;
[queryBtn addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[queryBtn sizeToFit];
[self.view addSubview:queryBtn];
//Core Data
x = 200,y = 50;
UILabel *coreDataLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
coreDataLabel.text = @"coreData";
[coreDataLabel sizeToFit];
[self.view addSubview:coreDataLabel];
x -= 5;
y += 50;
UIButton *addBtn1 = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[addBtn1 setTitle:@"add" forState:UIControlStateNormal];
[addBtn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
addBtn1.tag = 4;
[addBtn1 addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[addBtn1 sizeToFit];
[self.view addSubview:addBtn1];
y += 50;
UIButton *deleteBtn1 = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[deleteBtn1 setTitle:@"delete" forState:UIControlStateNormal];
[deleteBtn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
deleteBtn1.tag = 5;
[deleteBtn1 addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[deleteBtn1 sizeToFit];
[self.view addSubview:deleteBtn1];
y += 50;
UIButton *changeBtn1 = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[changeBtn1 setTitle:@"change" forState:UIControlStateNormal];
[changeBtn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
changeBtn1.tag = 6;
[changeBtn1 addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[changeBtn1 sizeToFit];
[self.view addSubview:changeBtn1];
y += 50;
UIButton *queryBtn1 = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 10, 10)];
[queryBtn1 setTitle:@"query" forState:UIControlStateNormal];
[queryBtn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
queryBtn1.tag = 7;
[queryBtn1 addTarget:self action:@selector(operetionClick:) forControlEvents:UIControlEventTouchUpInside];
[queryBtn1 sizeToFit];
[self.view addSubview:queryBtn1];
}
@end