ios CoreData和FMDB最新使用問題總結

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章