標籤:fmdb 反射 kvc
上次實現FMDB的CURD基本操作後,用在項目裡,每個實體類都要寫SQL語句來實現建立表和CURD操作,總覺得太麻煩,然後就想著利用反射和kvc來實現一個資料庫操作的基類繼承一下,子類只需要繼承,然後添加自己的屬性就好,這裡做一個總結。
第一個痛點:擷取子類的所有屬性以及類型
OC中有提供擷取所有property的方法,需要用到objc_property_t和class_copyPropertyList。
objc_property_t *properties =class_copyPropertyList([selfclass], &outCount); 數組properties有所有的屬性以及其相應的屬性類型。具體的代碼如下:
/** * 擷取該類的所有屬性 */+ (NSDictionary *)getPropertys{ NSMutableArray *proNames = [NSMutableArray array]; NSMutableArray *proTypes = [NSMutableArray array]; NSArray *theTransients = [[self class] transients]; unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList([self class], &outCount); for (i = 0; i < outCount; i++) { objc_property_t property = properties[i]; //擷取屬性名稱 NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding]; if ([theTransients containsObject:propertyName]) { continue; } [proNames addObject:propertyName]; //擷取屬性類型等參數 NSString *propertyType = [NSString stringWithCString: property_getAttributes(property) encoding:NSUTF8StringEncoding]; /* c char C unsigned char i int I unsigned int l long L unsigned long s short S unsigned short d double D unsigned double f float F unsigned float q long long Q unsigned long long B BOOL @ 物件類型 //指標 物件類型 如NSString 是@“NSString” 64位下long 和long long 都是Tq SQLite 預設支援五種資料類型TEXT、INTEGER、REAL、BLOB、NULL */ if ([propertyType hasPrefix:@"[email protected]"]) { [proTypes addObject:SQLTEXT]; } else if ([propertyType hasPrefix:@"Ti"]||[propertyType hasPrefix:@"TI"]||[propertyType hasPrefix:@"Ts"]||[propertyType hasPrefix:@"TS"]||[propertyType hasPrefix:@"TB"]) { [proTypes addObject:SQLINTEGER]; } else { [proTypes addObject:SQLREAL]; } } free(properties); return [NSDictionary dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",nil];}propertyTpe 在Xcode document 中,
類型主要是在建立表的時候需要用到,SQLite只支援五種資料類型TEXT、INTEGER、REAL、BLOB、NULL,這裡就需要將擷取到得屬性的類型轉換一下,我主要用了TEXT/INTEGER/REAL三種。
然後就是拼接SQL語句了,這個也比較簡單,建立表的SQL語句拼接在這裡:
+ (NSString *)getColumeAndTypeString{ NSMutableString* pars = [NSMutableString string]; NSDictionary *dict = [self.class getAllProperties]; NSMutableArray *proNames = [dict objectForKey:@"name"]; NSMutableArray *proTypes = [dict objectForKey:@"type"]; for (int i=0; i< proNames.count; i++) { [pars appendFormat:@"%@ %@",[proNames objectAtIndex:i],[proTypes objectAtIndex:i]]; if(i+1 != proNames.count) { [pars appendString:@","]; } } return pars;}第二個痛點:查詢出來的資料賦值給對象的對應屬性
這裡用到了KVC來賦值,主要方法就是setValue:forKey:
依然是先判斷屬性的類型,然後轉換相應的資料類型,我這裡主要是NSString和NSNumber。
if ([columeType isEqualToString:SQLTEXT]) { [model setValue:[resultSet stringForColumn:columeName] forKey:columeName]; } else { [model setValue:[NSNumber numberWithLongLong:[resultSet longLongIntForColumn:columeName]] forKey:columeName]; }
第三個痛點:子類在執行個體化時,直接建立對應的資料庫表,這裡用dispatch_once實現,只需要建立一次。子類中覆寫createTable方法。
+ (BOOL)createTable{ __block BOOL result = YES; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ result = [super createTable]; }); return result;}因為會有多線程操作,所以用單例和FMDatabaseQueue來執行,要避免queue裡調用queue執行操作。
有一些屬性不需要與資料庫表欄位對應,覆寫方法+ (NSArray *)transients;在改方法中返回不需要映射的欄位數組。
基類中的方法如下:
/** * 擷取該類的所有屬性 */+ (NSDictionary *)getPropertys;/** 擷取所有屬性,包括主鍵 */+ (NSDictionary *)getAllProperties;/** 資料庫中是否存在表 */+ (BOOL)isExistInTable;/** 儲存或更新 * 如果不存在主鍵,儲存, * 有主鍵,則更新 */- (BOOL)saveOrUpdate;/** 儲存單個資料 */- (BOOL)save;/** 批量儲存資料 */+ (BOOL)saveObjects:(NSArray *)array;/** 更新單個資料 */- (BOOL)update;/** 批次更新資料*/+ (BOOL)updateObjects:(NSArray *)array;/** 刪除單個資料 */- (BOOL)deleteObject;/** 大量刪除資料 */+ (BOOL)deleteObjects:(NSArray *)array;/** 通過條件刪除資料 */+ (BOOL)deleteObjectsByCriteria:(NSString *)criteria;/** 查詢全部資料 */+ (NSArray *)findAll;/** 通過主鍵查詢 */+ (instancetype)findByPK:(int)inPk;/** 尋找某條資料 */+ (instancetype)findFirstByCriteria:(NSString *)criteria;/** 通過條件尋找資料 * 這樣可以進行分頁查詢 @" WHERE pk > 5 limit 10" */+ (NSArray *)findByCriteria:(NSString *)criteria;#pragma mark - must be override method/** * 建立表 * 如果已經建立,返回YES */+ (BOOL)createTable;/** 如果子類中有一些property不需要建立資料庫欄位,那麼這個方法必須在子類中重寫 */+ (NSArray *)transients;
具體用法請轉到github下載源碼:https://github.com/Joker-King/JKDBModel
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
一行代碼實現FMDB的CURD操作