NSObject+LKModel.m 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. //
  2. // NSObject+LKModel.m
  3. // LKDBHelper
  4. //
  5. // Created by LJH on 13-4-15.
  6. // Copyright (c) 2013年 ljh. All rights reserved.
  7. //
  8. #import "LKDBHelper.h"
  9. #import "NSObject+LKModel.h"
  10. #import <objc/runtime.h>
  11. #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
  12. #import <UIKit/UIKit.h>
  13. #define LKDBImage UIImage
  14. #define LKDBColor UIColor
  15. #else
  16. #import <AppKit/AppKit.h>
  17. #define LKDBImage NSImage
  18. #define LKDBColor NSColor
  19. #endif
  20. static char LKModelBase_Key_RowID;
  21. static char LKModelBase_Key_TableName;
  22. static char LKModelBase_Key_Inserting;
  23. @interface LKDBHelper (LKDBHelper_LKModel)
  24. + (BOOL)nullIsEmpty;
  25. @end
  26. @implementation NSObject (LKModel)
  27. + (LKDBHelper *)getUsingLKDBHelper {
  28. ///ios8 能获取系统类的属性了 所以没有办法判断属性数量来区分自定义类和系统类
  29. ///可能系统类的存取会不正确
  30. static LKDBHelper *helper;
  31. static dispatch_once_t onceToken;
  32. dispatch_once(&onceToken, ^{
  33. helper = [[LKDBHelper alloc] init];
  34. });
  35. return helper;
  36. }
  37. #pragma mark Tabel Structure Function 表结构
  38. + (NSString *)getTableName {
  39. return NSStringFromClass(self);
  40. }
  41. + (NSString *)getPrimaryKey {
  42. return @"rowid";
  43. }
  44. + (NSArray *)getPrimaryKeyUnionArray {
  45. return nil;
  46. }
  47. + (void)columnAttributeWithProperty:(LKDBProperty *)property {
  48. //overwrite
  49. }
  50. #pragma 属性
  51. - (void)setRowid:(NSInteger)rowid {
  52. objc_setAssociatedObject(self, &LKModelBase_Key_RowID, [NSNumber numberWithInteger:rowid], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  53. }
  54. - (NSInteger)rowid {
  55. return [objc_getAssociatedObject(self, &LKModelBase_Key_RowID) integerValue];
  56. }
  57. - (void)setDb_tableName:(NSString *)db_tableName {
  58. objc_setAssociatedObject(self, &LKModelBase_Key_TableName, db_tableName, OBJC_ASSOCIATION_COPY_NONATOMIC);
  59. }
  60. - (NSString *)db_tableName {
  61. NSString *tableName = objc_getAssociatedObject(self, &LKModelBase_Key_TableName);
  62. if (tableName.length == 0) {
  63. tableName = [self.class getTableName];
  64. }
  65. return tableName;
  66. }
  67. - (BOOL)db_inserting {
  68. return [objc_getAssociatedObject(self, &LKModelBase_Key_Inserting) boolValue];
  69. }
  70. - (void)setDb_inserting:(BOOL)db_inserting {
  71. NSNumber *number = nil;
  72. if (db_inserting) {
  73. number = [NSNumber numberWithBool:YES];
  74. }
  75. objc_setAssociatedObject(self, &LKModelBase_Key_Inserting, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  76. }
  77. #pragma 无关紧要的
  78. + (NSString *)getDBImagePathWithName:(NSString *)filename {
  79. NSString *dir = [NSString stringWithFormat:@"dbimg/%@", NSStringFromClass(self)];
  80. return [LKDBUtils getPathForDocuments:filename inDir:dir];
  81. }
  82. + (NSString *)getDBDataPathWithName:(NSString *)filename {
  83. NSString *dir = [NSString stringWithFormat:@"dbdata/%@", NSStringFromClass(self)];
  84. return [LKDBUtils getPathForDocuments:filename inDir:dir];
  85. }
  86. #pragma mark - Table Data Function 表数据
  87. + (NSDateFormatter *)getModelDateFormatter {
  88. return nil;
  89. }
  90. ///get
  91. - (id)modelGetValue:(LKDBProperty *)property {
  92. NSString * const pKey = property.propertyName;
  93. id const value = [self valueForKey:pKey];
  94. id returnValue = value;
  95. if (value == nil) {
  96. return nil;
  97. } else if ([value isKindOfClass:[NSString class]]) {
  98. returnValue = [value copy];
  99. } else if ([value isKindOfClass:[NSNumber class]]) {
  100. returnValue = [[LKDBUtils numberFormatter] stringFromNumber:value];
  101. } else if ([value isKindOfClass:[NSDate class]]) {
  102. NSDateFormatter *formatter = [self.class getModelDateFormatter];
  103. if (formatter) {
  104. returnValue = [formatter stringFromDate:value];
  105. } else {
  106. returnValue = [LKDBUtils stringWithDate:value];
  107. }
  108. returnValue = [returnValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  109. } else if ([value isKindOfClass:[LKDBColor class]]) {
  110. LKDBColor *color = value;
  111. CGFloat r, g, b, a;
  112. [color getRed:&r green:&g blue:&b alpha:&a];
  113. returnValue = [NSString stringWithFormat:@"%.3f,%.3f,%.3f,%.3f", r, g, b, a];
  114. } else if ([value isKindOfClass:[NSValue class]]) {
  115. NSString *columnType = property.propertyType;
  116. #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
  117. if ([columnType isEqualToString:@"CGRect"]) {
  118. returnValue = NSStringFromCGRect([value CGRectValue]);
  119. } else if ([columnType isEqualToString:@"CGPoint"]) {
  120. returnValue = NSStringFromCGPoint([value CGPointValue]);
  121. } else if ([columnType isEqualToString:@"CGSize"]) {
  122. returnValue = NSStringFromCGSize([value CGSizeValue]);
  123. } else if ([columnType isEqualToString:@"_NSRange"]) {
  124. returnValue = NSStringFromRange([value rangeValue]);
  125. }
  126. #else
  127. if ([columnType hasSuffix:@"Rect"]) {
  128. returnValue = NSStringFromRect([value rectValue]);
  129. } else if ([columnType hasSuffix:@"Point"]) {
  130. returnValue = NSStringFromPoint([value pointValue]);
  131. } else if ([columnType hasSuffix:@"Size"]) {
  132. returnValue = NSStringFromSize([value sizeValue]);
  133. } else if ([columnType hasSuffix:@"Range"]) {
  134. returnValue = NSStringFromRange([value rangeValue]);
  135. }
  136. #endif
  137. } else if ([value isKindOfClass:[LKDBImage class]]) {
  138. long random = arc4random();
  139. long date = CFAbsoluteTimeGetCurrent();
  140. NSString *filename = [NSString stringWithFormat:@"img%ld%ld", date & 0xFFFFF, random & 0xFFF];
  141. #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
  142. NSData *datas = UIImageJPEGRepresentation(value, 1);
  143. #else
  144. [value lockFocus];
  145. NSBitmapImageRep *srcImageRep = [NSBitmapImageRep imageRepWithData:[value TIFFRepresentation]];
  146. NSData *datas = [srcImageRep representationUsingType:NSJPEGFileType properties:@{}];
  147. [value unlockFocus];
  148. #endif
  149. [datas writeToFile:[self.class getDBImagePathWithName:filename]
  150. atomically:YES];
  151. returnValue = filename;
  152. } else if ([value isKindOfClass:[NSData class]]) {
  153. long random = arc4random();
  154. long date = CFAbsoluteTimeGetCurrent();
  155. NSString *filename = [NSString stringWithFormat:@"data%ld%ld", date & 0xFFFFF, random & 0xFFF];
  156. [value writeToFile:[self.class getDBDataPathWithName:filename] atomically:YES];
  157. returnValue = filename;
  158. } else if ([value isKindOfClass:[NSURL class]]) {
  159. returnValue = [value absoluteString];
  160. } else {
  161. if ([value isKindOfClass:[NSArray class]]) {
  162. returnValue = [self db_jsonObjectFromArray:value pKey:pKey];
  163. } else if ([value isKindOfClass:[NSDictionary class]]) {
  164. returnValue = [self db_jsonObjectFromDictionary:value pKey:pKey];
  165. } else {
  166. returnValue = [self db_jsonObjectFromModel:value pKey:pKey];
  167. }
  168. returnValue = [self db_jsonStringFromObject:returnValue];
  169. }
  170. return returnValue;
  171. }
  172. ///set
  173. - (void)modelSetValue:(LKDBProperty *)property value:(NSString *)value {
  174. ///参试获取属性的Class
  175. Class columnClass = NSClassFromString(property.propertyType);
  176. id modelValue = nil;
  177. if (columnClass == nil) {
  178. ///当找不到 class 时,就是 基础类型 int,float CGRect 之类的
  179. NSString *columnType = property.propertyType;
  180. if ([LKSQL_Convert_FloatType rangeOfString:columnType].location != NSNotFound) {
  181. if (value) {
  182. modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
  183. }
  184. } else if ([LKSQL_Convert_IntType rangeOfString:columnType].location != NSNotFound) {
  185. if (value) {
  186. modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
  187. }
  188. }
  189. #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
  190. else if ([columnType isEqualToString:@"CGRect"]) {
  191. if (value) {
  192. CGRect rect = CGRectFromString(value);
  193. modelValue = [NSValue valueWithCGRect:rect];
  194. } else {
  195. modelValue = [NSValue valueWithCGRect:CGRectZero];
  196. }
  197. } else if ([columnType isEqualToString:@"CGPoint"]) {
  198. if (value) {
  199. CGPoint point = CGPointFromString(value);
  200. modelValue = [NSValue valueWithCGPoint:point];
  201. } else {
  202. modelValue = [NSValue valueWithCGPoint:CGPointZero];
  203. }
  204. } else if ([columnType isEqualToString:@"CGSize"]) {
  205. if (value) {
  206. CGSize size = CGSizeFromString(value);
  207. modelValue = [NSValue valueWithCGSize:size];
  208. } else {
  209. modelValue = [NSValue valueWithCGSize:CGSizeZero];
  210. }
  211. } else if ([columnType isEqualToString:@"_NSRange"]) {
  212. if (value) {
  213. NSRange range = NSRangeFromString(value);
  214. modelValue = [NSValue valueWithRange:range];
  215. } else {
  216. modelValue = [NSValue valueWithRange:NSMakeRange(0, 0)];
  217. }
  218. }
  219. #else
  220. else if ([columnType hasSuffix:@"Rect"]) {
  221. if (value) {
  222. NSRect rect = NSRectFromString(value);
  223. modelValue = [NSValue valueWithRect:rect];
  224. } else {
  225. modelValue = [NSValue valueWithRect:NSZeroRect];
  226. }
  227. } else if ([columnType hasSuffix:@"Point"]) {
  228. if (value) {
  229. NSPoint point = NSPointFromString(value);
  230. modelValue = [NSValue valueWithPoint:point];
  231. } else {
  232. modelValue = [NSValue valueWithPoint:NSZeroPoint];
  233. }
  234. } else if ([columnType hasSuffix:@"Size"]) {
  235. if (value) {
  236. NSSize size = NSSizeFromString(value);
  237. modelValue = [NSValue valueWithSize:size];
  238. } else {
  239. modelValue = [NSValue valueWithSize:NSZeroSize];
  240. }
  241. } else if ([columnType hasSuffix:@"Range"]) {
  242. if (value) {
  243. NSRange range = NSRangeFromString(value);
  244. modelValue = [NSValue valueWithRange:range];
  245. } else {
  246. modelValue = [NSValue valueWithRange:NSMakeRange(0, 0)];
  247. }
  248. }
  249. #endif
  250. ///如果都没有值 默认给个0
  251. if (modelValue == nil) {
  252. modelValue = @0;
  253. }
  254. } else if (!value || ![value isKindOfClass:[NSString class]]) {
  255. //不继续遍历
  256. } else if ([columnClass isSubclassOfClass:[NSString class]]) {
  257. if (![LKDBHelper nullIsEmpty] || value.length > 0) {
  258. modelValue = [columnClass stringWithString:value];
  259. }
  260. } else if ([columnClass isSubclassOfClass:[NSNumber class]]) {
  261. modelValue = [[LKDBUtils numberFormatter] numberFromString:value];
  262. } else if ([columnClass isSubclassOfClass:[NSDate class]]) {
  263. NSString *datestr = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  264. NSDateFormatter *formatter = [self.class getModelDateFormatter];
  265. if (formatter) {
  266. modelValue = [formatter dateFromString:datestr];
  267. } else {
  268. modelValue = [LKDBUtils dateWithString:datestr];
  269. }
  270. } else if ([columnClass isSubclassOfClass:[LKDBColor class]]) {
  271. NSString *colorString = value;
  272. NSArray *array = [colorString componentsSeparatedByString:@","];
  273. float r, g, b, a;
  274. r = [[array objectAtIndex:0] floatValue];
  275. g = [[array objectAtIndex:1] floatValue];
  276. b = [[array objectAtIndex:2] floatValue];
  277. a = [[array objectAtIndex:3] floatValue];
  278. modelValue = [LKDBColor colorWithRed:r green:g blue:b alpha:a];
  279. } else if ([columnClass isSubclassOfClass:[LKDBImage class]]) {
  280. NSString *filename = value;
  281. NSString *filepath = [self.class getDBImagePathWithName:filename];
  282. if ([LKDBUtils isFileExists:filepath]) {
  283. modelValue = [[LKDBImage alloc] initWithContentsOfFile:filepath];
  284. }
  285. } else if ([columnClass isSubclassOfClass:[NSData class]]) {
  286. NSString *filename = value;
  287. NSString *filepath = [self.class getDBDataPathWithName:filename];
  288. if ([LKDBUtils isFileExists:filepath]) {
  289. modelValue = [NSData dataWithContentsOfFile:filepath];
  290. }
  291. } else if ([columnClass isSubclassOfClass:[NSURL class]]) {
  292. NSString *urlString = value;
  293. modelValue = [NSURL URLWithString:urlString];
  294. } else {
  295. modelValue = [self db_modelWithJsonValue:value];
  296. BOOL isValid = NO;
  297. if ([modelValue isKindOfClass:[NSArray class]] && [columnClass isSubclassOfClass:[NSArray class]]) {
  298. isValid = YES;
  299. modelValue = [columnClass arrayWithArray:modelValue];
  300. } else if ([modelValue isKindOfClass:[NSDictionary class]] && [columnClass isSubclassOfClass:[NSDictionary class]]) {
  301. isValid = YES;
  302. modelValue = [columnClass dictionaryWithDictionary:modelValue];
  303. } else if ([modelValue isKindOfClass:columnClass]) {
  304. isValid = YES;
  305. }
  306. ///如果类型不对 则设置为空
  307. if (!isValid) {
  308. modelValue = nil;
  309. }
  310. }
  311. [self setValue:modelValue forKey:property.propertyName];
  312. }
  313. #pragma mark - 对 model NSArray NSDictionary 进行支持
  314. - (id)db_jsonObjectFromDictionary:(NSDictionary *)dic pKey:(NSString *)pKey {
  315. if ([NSJSONSerialization isValidJSONObject:dic]) {
  316. NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_JSON, LKDB_ValueKey: dic};
  317. return bomb;
  318. } else {
  319. NSMutableDictionary *toDic = [NSMutableDictionary dictionary];
  320. [dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
  321. id jsonObject = [self db_jsonObjectWithObject:obj pKey:pKey];
  322. if (jsonObject) {
  323. toDic[key] = jsonObject;
  324. }
  325. }];
  326. if (toDic.count) {
  327. NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_Combo, LKDB_ValueKey: toDic};
  328. return bomb;
  329. }
  330. }
  331. return nil;
  332. }
  333. - (id)db_jsonObjectFromArray:(NSArray *)array pKey:(NSString *)pKey {
  334. if ([NSJSONSerialization isValidJSONObject:array]) {
  335. NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_JSON, LKDB_ValueKey: array};
  336. return bomb;
  337. } else {
  338. NSMutableArray *toArray = [NSMutableArray array];
  339. NSInteger count = array.count;
  340. for (NSInteger i = 0; i < count; i++) {
  341. id obj = [array objectAtIndex:i];
  342. id jsonObject = [self db_jsonObjectWithObject:obj pKey:pKey];
  343. if (jsonObject) {
  344. [toArray addObject:jsonObject];
  345. }
  346. }
  347. if (toArray.count) {
  348. NSDictionary *bomb = @{LKDB_TypeKey: LKDB_TypeKey_Combo, LKDB_ValueKey: toArray};
  349. return bomb;
  350. }
  351. }
  352. return nil;
  353. }
  354. ///目前只支持 model、NSString、NSNumber 简单类型
  355. - (id)db_jsonObjectWithObject:(id)obj pKey:(NSString *)pKey {
  356. id jsonObject = nil;
  357. if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
  358. jsonObject = obj;
  359. } else if ([obj isKindOfClass:[NSDate class]]) {
  360. NSString *dateString = nil;
  361. NSDateFormatter *formatter = [self.class getModelDateFormatter];
  362. if (formatter) {
  363. dateString = [formatter stringFromDate:obj];
  364. } else {
  365. dateString = [LKDBUtils stringWithDate:obj];
  366. }
  367. dateString = [dateString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  368. if (dateString.length > 0) {
  369. jsonObject = @{LKDB_TypeKey: LKDB_TypeKey_Date, LKDB_ValueKey: dateString};
  370. }
  371. } else if ([obj isKindOfClass:[NSArray class]]) {
  372. jsonObject = [self db_jsonObjectFromArray:obj pKey:pKey];
  373. } else if ([obj isKindOfClass:[NSDictionary class]]) {
  374. jsonObject = [self db_jsonObjectFromDictionary:obj pKey:pKey];
  375. } else {
  376. jsonObject = [self db_jsonObjectFromModel:obj pKey:pKey];
  377. }
  378. if (jsonObject == nil) {
  379. jsonObject = [obj description];
  380. }
  381. return jsonObject;
  382. }
  383. - (id)db_jsonObjectFromModel:(NSObject *)model pKey:(NSString *)pKey {
  384. Class clazz = model.class;
  385. NSDictionary *jsonObject = nil;
  386. if (model.rowid > 0) {
  387. [model updateToDB];
  388. jsonObject = [self db_readInfoWithModel:model class:clazz];
  389. } else {
  390. if (model.db_inserting == NO && [clazz getModelInfos].count > 0) {
  391. BOOL success = [model saveToDB];
  392. if (success) {
  393. jsonObject = [self db_readInfoWithModel:model class:clazz];
  394. }
  395. } else {
  396. NSAssert(NO, @"目前LKDB不支持循环引用。Model:%@ Key:%@ Value:%@", self, pKey, model);
  397. }
  398. }
  399. return jsonObject;
  400. }
  401. - (NSDictionary *)db_readInfoWithModel:(NSObject *)model class:(Class)clazz {
  402. NSMutableDictionary *jsonObject = [NSMutableDictionary dictionary];
  403. if (!model.db_tableName) {
  404. NSAssert(NO, @"none table name");
  405. return nil;
  406. }
  407. if (!NSStringFromClass(clazz)) {
  408. NSAssert(NO, @"none class");
  409. return nil;
  410. }
  411. jsonObject[LKDB_TypeKey] = LKDB_TypeKey_Model;
  412. jsonObject[LKDB_TableNameKey] = model.db_tableName;
  413. jsonObject[LKDB_ClassKey] = NSStringFromClass(clazz);
  414. jsonObject[LKDB_RowIdKey] = @(model.rowid);
  415. NSDictionary *dic = [model db_getPrimaryKeysValues];
  416. if (dic.count > 0 && [NSJSONSerialization isValidJSONObject:dic]) {
  417. jsonObject[LKDB_PValueKey] = dic;
  418. }
  419. return jsonObject;
  420. }
  421. - (NSString *)db_jsonStringFromObject:(NSObject *)jsonObject {
  422. if (jsonObject && [NSJSONSerialization isValidJSONObject:jsonObject]) {
  423. NSData *data = [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:nil];
  424. if (data.length > 0) {
  425. NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  426. return jsonString;
  427. }
  428. }
  429. return nil;
  430. }
  431. - (id)db_modelWithJsonValue:(id)value {
  432. NSData *jsonData = nil;
  433. if ([value isKindOfClass:[NSString class]]) {
  434. jsonData = [value dataUsingEncoding:NSUTF8StringEncoding];
  435. } else if ([value isKindOfClass:[NSData class]]) {
  436. jsonData = value;
  437. }
  438. if (jsonData.length > 0) {
  439. NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
  440. return [self db_objectWithDictionary:jsonDic];
  441. }
  442. return nil;
  443. }
  444. - (id)db_objectWithArray:(NSArray *)array {
  445. NSMutableArray *toArray = nil;
  446. NSInteger count = array.count;
  447. for (NSInteger i = 0; i < count; i++) {
  448. id value = [array objectAtIndex:i];
  449. if ([value isKindOfClass:[NSDictionary class]]) {
  450. value = [self db_objectWithDictionary:value];
  451. } else if ([value isKindOfClass:[NSArray class]]) {
  452. value = [self db_objectWithArray:value];
  453. }
  454. if (value) {
  455. if (toArray == nil) {
  456. toArray = [NSMutableArray array];
  457. }
  458. [toArray addObject:value];
  459. }
  460. }
  461. return toArray;
  462. }
  463. - (id)db_objectWithDictionary:(NSDictionary *)dic {
  464. if (dic.count == 0) {
  465. return nil;
  466. }
  467. NSString *type = [dic objectForKey:LKDB_TypeKey];
  468. if (type) {
  469. if ([type isEqualToString:LKDB_TypeKey_Model]) {
  470. Class clazz = NSClassFromString([dic objectForKey:LKDB_ClassKey]);
  471. NSInteger rowid = [[dic objectForKey:LKDB_RowIdKey] integerValue];
  472. NSString *tableName = [dic objectForKey:LKDB_TableNameKey];
  473. NSString *subSQL = nil;
  474. NSString *rowCountWhere = [NSString stringWithFormat:@"select count(rowid) from %@ where rowid=%ld limit 1", tableName, (long)rowid];
  475. NSInteger result = [[[clazz getUsingLKDBHelper] executeScalarWithSQL:rowCountWhere arguments:nil] integerValue];
  476. if (result > 0) {
  477. subSQL = [NSString stringWithFormat:@"select rowid,* from %@ where rowid=%ld limit 1", tableName, (long)rowid];
  478. } else {
  479. NSDictionary *pv = [dic objectForKey:LKDB_PValueKey];
  480. if (pv.count > 0) {
  481. BOOL isNeedAddDot = NO;
  482. NSMutableString *mutableString = [NSMutableString stringWithFormat:@"select rowid,* from %@ where", tableName];
  483. NSArray *allKeys = pv.allKeys;
  484. for (NSString *key in allKeys) {
  485. id obj = [pv objectForKey:key];
  486. if (isNeedAddDot) {
  487. [mutableString appendString:@" and"];
  488. }
  489. [mutableString appendFormat:@" %@ = '%@'", key, obj];
  490. isNeedAddDot = YES;
  491. }
  492. [mutableString appendString:@" limit 1"];
  493. subSQL = mutableString.copy;
  494. }
  495. }
  496. if (subSQL.length > 0) {
  497. NSArray *array = [[clazz getUsingLKDBHelper] searchWithSQL:subSQL toClass:clazz];
  498. if (array.count > 0) {
  499. NSObject *result = [array objectAtIndex:0];
  500. result.db_tableName = tableName;
  501. return result;
  502. }
  503. }
  504. } else if ([type isEqualToString:LKDB_TypeKey_JSON]) {
  505. id value = [dic objectForKey:LKDB_ValueKey];
  506. return value;
  507. } else if ([type isEqualToString:LKDB_TypeKey_Combo]) {
  508. id value = [dic objectForKey:LKDB_ValueKey];
  509. if ([value isKindOfClass:[NSArray class]]) {
  510. return [self db_objectWithArray:value];
  511. } else if ([value isKindOfClass:[NSDictionary class]]) {
  512. return [self db_objectWithDictionary:value];
  513. } else {
  514. return value;
  515. }
  516. } else if ([type isEqualToString:LKDB_TypeKey_Date]) {
  517. NSString *datestr = [dic objectForKey:LKDB_ValueKey];
  518. NSDateFormatter *formatter = [self.class getModelDateFormatter];
  519. if (formatter) {
  520. return [formatter dateFromString:datestr];
  521. } else {
  522. return [LKDBUtils dateWithString:datestr];
  523. }
  524. }
  525. } else {
  526. NSMutableDictionary *toDic = [NSMutableDictionary dictionary];
  527. [dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
  528. id saveObj = value;
  529. if ([value isKindOfClass:[NSArray class]]) {
  530. saveObj = [self db_objectWithArray:value];
  531. } else if ([value isKindOfClass:[NSDictionary class]]) {
  532. saveObj = [self db_objectWithDictionary:value];
  533. }
  534. if (saveObj) {
  535. toDic[key] = saveObj;
  536. }
  537. }];
  538. return toDic;
  539. }
  540. return nil;
  541. }
  542. #pragma mark - your can overwrite
  543. - (void)setNilValueForKey:(NSString *)key {
  544. MOLogV(@"nil 这种设置到了 int 等基础类型中");
  545. }
  546. - (id)valueForUndefinedKey:(NSString *)key {
  547. MOLogV(@"你有get方法没实现,key:%@", key);
  548. return nil;
  549. }
  550. - (void)setValue:(id)value forUndefinedKey:(NSString *)key {
  551. MOLogV(@"你有set方法没实现,key:%@", key);
  552. }
  553. #pragma mark -
  554. - (void)userSetValueForModel:(LKDBProperty *)property value:(id)value {
  555. }
  556. - (id)userGetValueForModel:(LKDBProperty *)property {
  557. return nil;
  558. }
  559. - (NSDictionary *)db_getPrimaryKeysValues {
  560. LKModelInfos *infos = [self.class getModelInfos];
  561. NSArray *array = infos.primaryKeys;
  562. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  563. [array enumerateObjectsUsingBlock:^(NSString *pname, NSUInteger idx, BOOL *_Nonnull stop) {
  564. LKDBProperty *property = [infos objectWithSqlColumnName:pname];
  565. id value = nil;
  566. if ([property.type isEqualToString:LKSQL_Mapping_UserCalculate]) {
  567. value = [self userGetValueForModel:property];
  568. } else {
  569. value = [self modelGetValue:property];
  570. }
  571. if (value) {
  572. dic[property.sqlColumnName] = value;
  573. }
  574. }];
  575. return dic;
  576. }
  577. //主键值 是否为空
  578. - (BOOL)singlePrimaryKeyValueIsEmpty {
  579. LKDBProperty *property = [self singlePrimaryKeyProperty];
  580. if (property) {
  581. id pkvalue = [self singlePrimaryKeyValue];
  582. if ([property.sqlColumnType isEqualToString:LKSQL_Type_Int]) {
  583. if ([pkvalue isKindOfClass:[NSString class]]) {
  584. if ([LKDBUtils checkStringIsEmpty:pkvalue])
  585. return YES;
  586. if ([pkvalue integerValue] == 0)
  587. return YES;
  588. return NO;
  589. }
  590. if ([pkvalue isKindOfClass:[NSNumber class]]) {
  591. if ([pkvalue integerValue] == 0)
  592. return YES;
  593. else
  594. return NO;
  595. }
  596. return YES;
  597. } else {
  598. return (pkvalue == nil);
  599. }
  600. }
  601. return NO;
  602. }
  603. - (LKDBProperty *)singlePrimaryKeyProperty {
  604. LKModelInfos *infos = [self.class getModelInfos];
  605. if (infos.primaryKeys.count == 1) {
  606. NSString *name = [infos.primaryKeys objectAtIndex:0];
  607. return [infos objectWithSqlColumnName:name];
  608. }
  609. return nil;
  610. }
  611. - (id)singlePrimaryKeyValue {
  612. LKDBProperty *property = [self singlePrimaryKeyProperty];
  613. if (property) {
  614. if ([property.type isEqualToString:LKSQL_Mapping_UserCalculate]) {
  615. return [self userGetValueForModel:property];
  616. } else {
  617. return [self modelGetValue:property];
  618. }
  619. }
  620. return nil;
  621. }
  622. + (NSString *)db_rowidAliasName {
  623. LKModelInfos *infos = [self getModelInfos];
  624. if (infos.primaryKeys.count == 1) {
  625. NSString *primaryType = [infos objectWithSqlColumnName:[infos.primaryKeys lastObject]].sqlColumnType;
  626. if ([primaryType isEqualToString:LKSQL_Type_Int]) {
  627. return [infos.primaryKeys lastObject];
  628. }
  629. }
  630. return nil;
  631. }
  632. #pragma mark - get model property info
  633. + (LKModelInfos *)getModelInfos {
  634. static __strong NSMutableDictionary *oncePropertyDic;
  635. static __strong NSRecursiveLock *lock;
  636. static dispatch_once_t onceToken;
  637. dispatch_once(&onceToken, ^{
  638. lock = [[NSRecursiveLock alloc] init];
  639. oncePropertyDic = [[NSMutableDictionary alloc] initWithCapacity:8];
  640. });
  641. LKModelInfos *infos;
  642. [lock lock];
  643. NSString *className = NSStringFromClass(self);
  644. infos = [oncePropertyDic objectForKey:className];
  645. if (infos == nil) {
  646. NSMutableArray *pronames = [NSMutableArray array];
  647. NSMutableArray *protypes = [NSMutableArray array];
  648. NSDictionary *keymapping = [self getTableMapping];
  649. if ([self isContainSelf] && self != [NSObject class]) {
  650. [self getSelfPropertys:pronames protypes:protypes];
  651. }
  652. NSArray *pkArray = [self getPrimaryKeyUnionArray];
  653. if (pkArray.count == 0) {
  654. pkArray = nil;
  655. NSString *pk = [self getPrimaryKey];
  656. if ([LKDBUtils checkStringIsEmpty:pk] == NO) {
  657. pkArray = [NSArray arrayWithObject:pk];
  658. }
  659. }
  660. if ([self isContainParent] && [self superclass] != [NSObject class]) {
  661. LKModelInfos *superInfos = [[self superclass] getModelInfos];
  662. for (NSInteger i = 0; i < superInfos.count; i++) {
  663. LKDBProperty *db_p = [superInfos objectWithIndex:i];
  664. if (db_p.propertyName && db_p.propertyType && [db_p.propertyName isEqualToString:@"rowid"] == NO) {
  665. [pronames addObject:db_p.propertyName];
  666. [protypes addObject:db_p.propertyType];
  667. }
  668. }
  669. }
  670. if (pronames.count > 0) {
  671. infos = [[LKModelInfos alloc] initWithKeyMapping:keymapping propertyNames:pronames propertyType:protypes primaryKeys:pkArray];
  672. } else {
  673. infos = [[LKModelInfos alloc] init];
  674. }
  675. oncePropertyDic[className] = infos;
  676. }
  677. [lock unlock];
  678. return infos;
  679. }
  680. + (BOOL)isContainParent {
  681. return NO;
  682. }
  683. + (BOOL)isContainSelf {
  684. return YES;
  685. }
  686. /**
  687. * @brief 获取自身的属性
  688. *
  689. * @param pronames 保存属性名称
  690. * @param protypes 保存属性类型
  691. */
  692. + (void)getSelfPropertys:(NSMutableArray *)pronames protypes:(NSMutableArray *)protypes {
  693. unsigned int outCount = 0, i = 0;
  694. objc_property_t *properties = class_copyPropertyList(self, &outCount);
  695. for (i = 0; i < outCount; i++) {
  696. objc_property_t property = properties[i];
  697. NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
  698. //取消rowid 的插入 //子类 已重载的属性 取消插入
  699. if (propertyName.length == 0 || [propertyName isEqualToString:@"rowid"] ||
  700. [pronames indexOfObject:propertyName] != NSNotFound) {
  701. continue;
  702. }
  703. NSString *propertyType = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
  704. ///过滤只读属性
  705. if ([propertyType rangeOfString:@",R,"].length > 0 || [propertyType hasSuffix:@",R"]) {
  706. NSString *firstWord = [[propertyName substringToIndex:1] uppercaseString];
  707. NSString *otherWord = [propertyName substringFromIndex:1];
  708. NSString *setMethodString = [NSString stringWithFormat:@"set%@%@:", firstWord, otherWord];
  709. SEL setSEL = NSSelectorFromString(setMethodString);
  710. ///有set方法就不过滤了
  711. if ([self instancesRespondToSelector:setSEL] == NO) {
  712. continue;
  713. }
  714. }
  715. /*
  716. c char
  717. i int
  718. l long
  719. s short
  720. d double
  721. f float
  722. @ id //指针 对象
  723. ... BOOL 获取到的表示 方式是 char
  724. .... ^i 表示 int * 一般都不会用到
  725. */
  726. NSString *propertyClassName = nil;
  727. if ([propertyType hasPrefix:@"T@"]) {
  728. NSRange range = [propertyType rangeOfString:@","];
  729. if (range.location > 4 && range.location <= propertyType.length) {
  730. range = NSMakeRange(3, range.location - 4);
  731. propertyClassName = [propertyType substringWithRange:range];
  732. if ([propertyClassName hasSuffix:@">"]) {
  733. NSRange categoryRange = [propertyClassName rangeOfString:@"<"];
  734. if (categoryRange.length > 0) {
  735. propertyClassName = [propertyClassName substringToIndex:categoryRange.location];
  736. }
  737. }
  738. }
  739. } else if ([propertyType hasPrefix:@"T{"]) {
  740. NSRange range = [propertyType rangeOfString:@"="];
  741. if (range.location > 2 && range.location <= propertyType.length) {
  742. range = NSMakeRange(2, range.location - 2);
  743. propertyClassName = [propertyType substringWithRange:range];
  744. }
  745. } else {
  746. propertyType = [propertyType lowercaseString];
  747. if ([propertyType hasPrefix:@"ti"] || [propertyType hasPrefix:@"tb"]) {
  748. propertyClassName = @"int";
  749. } else if ([propertyType hasPrefix:@"tf"]) {
  750. propertyClassName = @"float";
  751. } else if ([propertyType hasPrefix:@"td"]) {
  752. propertyClassName = @"double";
  753. } else if ([propertyType hasPrefix:@"tl"] || [propertyType hasPrefix:@"tq"]) {
  754. propertyClassName = @"long";
  755. } else if ([propertyType hasPrefix:@"tc"]) {
  756. propertyClassName = @"char";
  757. } else if ([propertyType hasPrefix:@"ts"]) {
  758. propertyClassName = @"short";
  759. }
  760. }
  761. if ([LKDBUtils checkStringIsEmpty:propertyClassName]) {
  762. ///没找到具体的属性就放弃
  763. continue;
  764. }
  765. ///添加属性
  766. [pronames addObject:propertyName];
  767. [protypes addObject:propertyClassName];
  768. }
  769. free(properties);
  770. if ([self isContainParent] && [self superclass] != [NSObject class]) {
  771. [[self superclass] getSelfPropertys:pronames protypes:protypes];
  772. }
  773. }
  774. #pragma mark - log all property
  775. - (NSMutableString *)getAllPropertysString {
  776. Class clazz = [self class];
  777. NSMutableString *sb = [NSMutableString stringWithFormat:@"\n <%@> :\n", NSStringFromClass(clazz)];
  778. [sb appendFormat:@"rowid : %ld\n", (long)self.rowid];
  779. [self mutableString:sb appendPropertyStringWithClass:clazz containParent:YES];
  780. return sb;
  781. }
  782. - (NSString *)printAllPropertys {
  783. return [self printAllPropertysIsContainParent:NO];
  784. }
  785. - (NSString *)printAllPropertysIsContainParent:(BOOL)containParent {
  786. #ifdef DEBUG
  787. Class clazz = [self class];
  788. NSMutableString *sb = [NSMutableString stringWithFormat:@"\n <%@> :\n", NSStringFromClass(clazz)];
  789. [sb appendFormat:@"rowid : %ld\n", (long)self.rowid];
  790. [self mutableString:sb appendPropertyStringWithClass:clazz containParent:containParent];
  791. MOLogV(@"%@", sb);
  792. return sb;
  793. #else
  794. return @"";
  795. #endif
  796. }
  797. - (void)mutableString:(NSMutableString *)sb appendPropertyStringWithClass:(Class)clazz containParent:(BOOL)containParent {
  798. if (clazz == [NSObject class]) {
  799. return;
  800. }
  801. unsigned int outCount = 0, i = 0;
  802. objc_property_t *properties = class_copyPropertyList(clazz, &outCount);
  803. for (i = 0; i < outCount; i++) {
  804. objc_property_t property = properties[i];
  805. NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
  806. [sb appendFormat:@" %@ : %@ \n", propertyName, [self valueForKey:propertyName]];
  807. }
  808. free(properties);
  809. if (containParent) {
  810. [self mutableString:sb appendPropertyStringWithClass:clazz.superclass containParent:containParent];
  811. }
  812. }
  813. @end