IOS开发者们在使用coreData和sqlite原生接口的问题上争论不休,使用coreData无疑更方便,
它也在变得更好,但是反对者们的枪口对准了其在处理大量数据时候的无力感,而且作为开发
者却束手无策。sqlite的鼓吹者们觉得自己手写sql更简介、更可控,还可以带来更好的性能。
FMDB这个简单易用的存储库,站在了以上两种观点的中间,基本上平衡了两种方式存在的种种
优缺点,获得了大量的开发者的青睐。
FMDB只是在sqlite上做了一层很薄的封装,但是却大大地提高了开发者的使用效率,其毕竟不
是大家耳熟能详的ORM,自然也不能享受到ORM带来的种种好处。下文中我们就来看看使用FMDB
来实现一些类似于ORM的类库。
LocalDBManager
LocalDBManager是直接与数据库交互的类,为了使代码更好维护,所有的持久化均要走这个类
的API才能写入数据库中,下面是其简要设计:
typedef void (^DBUpdateCallback)(NSError *error);
typedef void (^DBInsertCallback)(NSArray *ids, NSError *error);
typedef void (^DBQueryCallback)(FMResultSet *result, NSError *error);
typedef void (^DBExecuteCallback)(FMDatabase *db);
@interface LocalDBManager : NSObject
+ (instancetype)sharedInstance;
- (void)open;
- (void)close;
- (void)insertBatchAsync:(DBInsertCallback)callback insert:(NSString *)insert withArgsArray:(NSArray *)argsArray abortWhenError:(BOOL)abortWhenError;
- (void)updateBatchAsync:(DBUpdateCallback)callback update:(NSString *)update withArgsArray:(NSArray *)argsArray abortWhenError:(BOOL)abortWhenError;
- (void)queryAsync:(DBQueryCallback)callback query:(NSString *)query withArgs:(NSArray *)args;
- (void)execute:(DBExecuteCallback)callback;
@end
以上设计中,主要有如下要点:
- 对于数据库的增、删、改、查操作,强制提供批量Batch操作的接口,以增加数据库操作的效率。
- 在Batch操作中提供强制使用事务,提高Sqlite的速度。
- 在open操作中处理数据库的migrate,留出execute方法来处理一些复杂场景。
BaseModel
BaseModel作为Model的基类,所有的Model均继承自此类,所以在该类的实现中完成一些基本
动作,设计如下:
typedef void (^ModelQueryCallback)(NSArray *items, NSError *error);
typedef void (^ModelCallback)(NSError *error);
@interface BaseModel : NSObject
+ (NSString *)tableName;
+ (NSString *)primaryKeyName;
- (id)primaryKeyValue;
+ (void)queryAll:(ModelQueryCallback)callback;
+ (void)queryByOffset:(NSInteger)offset withSize:(NSInteger)size callback:(ModelQueryCallback)callback;
+ (void)removeBatch:(NSArray *)models callback:(ModelCallback)callback;
+ (void)insertBatch:(NSArray *)models callback:(ModelCallback)callback;
+ (void)insert:(BaseModel *)model callback:(ModelCallback)callback;
+ (void)updateBatch:(NSArray *)models callback:(ModelCallback)callback;
- (void)insert:(ModelCallback)callback;
- (void)update:(ModelCallback)callback;
- (void)remove:(ModelCallback)callback;
+ (void)modelCallbackOnMainThread:(ModelCallback)callback withError:(NSError *)error;
+ (void)modelQueryCallbackOnMainThread:(ModelQueryCallback)callback withItems:(NSArray *)items withError:(NSError *)error;
@end
以上设计中,主要有如下要点:
- tableName、primaryKeyName、primaryKeyValue需要子类来细化,所以必须被覆写。
- 其它的需要子类必须覆写的API有queryByOffset、insertBatch、updateBatch,其它的方法
均可在此基类中实现。 - 最后两个方法是对callback进行的优雅处理,由于其通用性,在基类中实现。
Model
Model即是我们需要持久化的模型,由于Model是重要的数据结构,所以一般习惯于把Model
写的很重,理论上可以在Model中实现所有的持久化操作,只是写数据库必须通过LocalDBManager
来完成,Model之间一些共有操作被提取到BaseModel中实现。再者并不是Model中所有的字段
与数据库中表字段一一对应,也可以在其中声明not in db的属性。下面来看看Model的一般设
计:
@interface User : BaseModel
+ (void)queryByOffset:(NSInteger)offset withSize:(NSInteger)size callback:(ModelQueryCallback)callback;
+ (void)updateBatch:(NSArray *)models callback:(ModelCallback)callback;
+ (void)insertBatch:(NSArray *)models callback:(ModelCallback)callback;
- (void)fillWith:(User *)user;
- (BOOL)isEqualToUser:(User *)aUser;
+ (NSArray *)convertToModel:(FMResultSet *)result
+ (void)query:(NSString *)sql withArgs:(NSArray *)args callback:(ModelQueryCallback)callback;
+ (void)queryById:(SInt64)userId callback:(ModelQueryCallback)callback;
@end
以上设计中,主要有一下要点:
- 前三个方法是必须要覆写的父类中方法,后两个方法是Model的特色方法,各个Model之间各异。
- 中间的两个方法是大部分Model中都会存在的方法。
总结
以上只是数据持久化写入数据库的一种通用方法,当然我们可以抽象出更多的protocal来让
Model去实现,使得Model封装的层次性更好,但是继承的深度不要再增加了,继承只会增加
程序的复杂度。
通过以上的讲解,相信你对于FMDB的使用方法和Model持久化有了更清醒的认识。
网友评论