IOS与sqlite及归档

起因


业务需求!以前项目都是用到归档!很小用数据库!所有特意研究sqlite数据库及其封装~~~

归档优缺点


  • 1 简单
  • 2 数据量大时效率低下,且不能增量改变,必须一次写入

数据库优缺

  • 1 可以增量改变
  • 2 相对于归档比较复杂

sqlite


sqlite 增删改查基本封装

使用


已封装为已类名为表头,一张表占一个库文件,直接引入*.h *.m 就可以用了

封装涉及知识点


  • 1 objc_property_t 动态获取实例属性(反射机制)
	 //实例类
    Class model_class = [model class];
    NSMutableDictionary * sub_model_info = [NSMutableDictionary dictionary];
    unsigned int property_count = 0;
    //类包含对象数量
    objc_property_t * propertys = class_copyPropertyList(model_class, &property_count);
    for (int i = 0; i < property_count; i++) {
	     //每个对象的属性
        objc_property_t property = propertys[i];
        //对象名
        const char * property_name = property_getName(property);
        //对象属性 
        const char * property_attributes = property_getAttributes(property);
        NSString * property_name_string = [NSString stringWithUTF8String:property_name];
        NSString * property_attributes_string = [NSString stringWithUTF8String:property_attributes];
        //基础类  备注:如 int,bool property_attributes_list.count = 1 
        NSArray * property_attributes_list = [property_attributes_string componentsSeparatedByString:@"\""];
        }
  • 2 sqlite 建表 字段

//将类对象利用 动态获取实例属性 ,根据类型判断转为sql语句,并且在语句创建时 必须加上_id(属性 主键且唯一),如遇到子类则递归创建方法 (建议 基本对象不要超过2层)

CREATE TABLE IF NOT EXISTS SqlTestModel (_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,dataVal BLOB DEFAULT NULL,boolVal INTERGER DEFAULT 0,numberVal INTERGER DEFAULT 0,subModel INTERGER DEFAULT 0,boolVal2 INTERGER DEFAULT 0)
  • 3 sqlite 改表 字段
// sqlite 没有删表的字段功能,所以曲线处理.

1.旧表改名

NSString* rename_table_sql = [NSString stringWithFormat:@"alter table %@ rename to temp_tab",table_name];

2.以新对象建表

3.判读新表含有哪些旧表字段

NSArray * new_model_field_name_array = [self getModelFieldNameWithClass:model_class];
NSMutableString * newField = [[NSMutableString alloc]init];
for (NSString* field in new_model_field_name_array) {
    NSInteger idx = [old_model_field_name_array indexOfObject:field];
    if (idx != NSNotFound) {
       [newField appendString:[NSString stringWithFormat:@"%@ ,",field]];
    }
}
            
4.导入旧表数据到新表

NSString* insert_table_sql = [NSString stringWithFormat:@"insert into %@(%@) select %@ from %@ where 1=1 ",table_name,newField,newField,@"temp_tab"];

5.删除旧表
NSString* drop_table_sql = [NSString stringWithFormat:@"drop table %@",@"temp_tab"];
  • 4 增删改查
注意事项

1. 要加锁

@property (nonatomic, strong) dispatch_semaphore_t dsema;
self.dsema = dispatch_semaphore_create(1);

+ (void)insert:(id)model_object {
    dispatch_semaphore_wait([self shareInstance].dsema, DISPATCH_TIME_FOREVER);
    @autoreleasepool {
//        [[self shareInstance].sub_model_info removeAllObjects];
//        [self insertModelObject:model_object];
    }
    dispatch_semaphore_signal([self shareInstance].dsema);
}

2. 要先处理自定义类里面,包含其自定义类,并优先存入

3. 多条命令写入,要加事务处理
[self execSql:@"BEIGIN"];
//要处理内容
[self execSql:@"COMMIT"];
  • 5 runtime技巧 setter getter
@interface PropertyInfo : NSObject
@property (nonatomic, assign, readonly) FieldType type;
@property (nonatomic, copy, readonly) NSString * name;
@property (nonatomic, assign, readonly) SEL setter;
@property (nonatomic, assign, readonly) SEL getter;
@end
@implementation PropertyInfo

- (PropertyInfo *)initWithType:(FieldType)type propertyName:(NSString *)property_name {
    self = [super init];
    if (self) {
        _name = property_name.mutableCopy;
        _type = type;
        _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",[property_name substringToIndex:1].uppercaseString,[property_name substringFromIndex:1]]);
        _getter = NSSelectorFromString(property_name);
    }
    return self;
}

@end
+ (id)querySubModel:(Class)model_class conditions:(NSArray *)conditions queryType:(QueryType)query_type;

id model_object = [model_class new];

//PropertyInfo 为一个model
PropertyInfo * property_info = field_dictionary[field_name];

//setter
NSNumber * value = @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model_object, property_info.getter));

//getter
((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model_object, property_info.setter, value);