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