閱讀此文時廊移,假設(shè)你已經(jīng)對Core Data 有了一定的認識,熟知Core Data 框架下的幾個類及基本的使用方法,對多線程操作也有一定的了解。怎么禁漓?你是剛剛接觸Core Data的跟衅?也不要急著走,來都來了,隨便看看吧谒撼,也沒有多少文字食寡。
概念##
關(guān)于Core Data 的介紹、各種使用說明cookbook 非常多廓潜,在簡書站內(nèi)搜一下抵皱,就能發(fā)現(xiàn)好幾篇非常詳盡的善榛、圖文并茂的文章,所以這一塊兒我就略過了呻畸。
坑##
使用過Core Data 的兄弟們移盆,或多或少會說,Core Data 不同于其它系統(tǒng)框架:難入門伤为、難提高咒循、蹦潰多,等等绞愚。網(wǎng)上大量的手冊叙甸、幫助,但都是基本概念位衩,只教你邁出第一步裆蒸,但你想歡快地??起來,往往還需要自己琢磨糖驴,你看僚祷,我就琢磨出一條土路,用著還挺順手遂赠,現(xiàn)將其封裝久妆,分享出來給各位,請不吝指教跷睦。
GFCoreDataSource##
install:
pod 'GFCoreDataSource'
or source: github (內(nèi)附demo)
源碼目錄結(jié)構(gòu):
GFCoreDataSource
|- GFCoreDataSource.h
|- GFDataSource.h
|- GFDataSource.m
|- GFObjectOperation.h
|- GFObjectOperation.m
如何使用筷弦?##
GFCoreDataSource
從名字也能看出來,這就是個數(shù)據(jù)源管理器抑诸,不錯烂琴,這個Data source 封裝了Core Data 對數(shù)據(jù)庫的查詢、寫入操作蜕乡,查詢操作在主線程奸绷,寫入操作在子線程,合并在主線程层玲,如果你的項目需要長時間處理大量的數(shù)據(jù)(超過萬條)号醉,那可能需要在子線程合并,我?guī)筒涣四阈量椋蛘吲吓桑ㄗh你采用性能表現(xiàn)更佳的 realm。
定義自己的Data Source###
先聲明一個基于GFDataSource
的data source
@interface MyDataSource : GFDataSource
@end
實例化
@implementation MyDataSource
+ (instancetype)sharedClient {
static dispatch_once_t onceToken;
static MyDataSource *client = nil;
dispatch_once(&onceToken, ^{
client = [[MyDataSource alloc] init];
});
return client;
}
- (instancetype)init {
if (self = [super initWithManagedObjectContext:managedObjectContext
coordinator:persistentStoreCoordinator
class:[MyObjectOperation class]]) {
}
return self;
}
@end
此Data source一個實例可以實現(xiàn)對同一個SQLite數(shù)據(jù)庫的多種查詢與修改監(jiān)聽润绵,所以线椰,一般只需要創(chuàng)建一個實例,建議用+ (instancetype)sharedClient;
方法來創(chuàng)建尘盼,其初始化時憨愉,需要傳入的三個參數(shù):
- managedObjectContext:NSManagedObjectContext 的實例烦绳,由主線程創(chuàng)建,查詢操作使用(因此配紫,查詢操作只能在主線程中使用)
- persistentStoreCoordinator:NSPersistentStoreCoordinator 的實例径密,子線程創(chuàng)建NSManagedObjectContext 實例時需要用到
- [MyObjectOperation class]:此處注冊了原子操作時對應(yīng)的類,此類中實現(xiàn)了具體的增笨蚁、刪睹晒、改操作趟庄,其聲明如下:
@interface MyObjectOperation : GFObjectOperation
@end
你需要實現(xiàn)相應(yīng)的方法:
@implementation MyObjectOperation
- (void)onAddObject:(id)object {
}
- (void)onEditObject:(NSManagedObject *)object edit:(NSDictionary *)edit {
}
- (void)onDeleteObject:(NSManagedObject *)object {
}
@end
注冊查詢括细、監(jiān)聽###
self.dataKey = @"viewListing";
self.dataSource = [MyDataSource sharedClient];
[self.dataSource registerDelegate:self
entity:[MyEntity entityName]
predicate:predicate
sortDescriptors:@[dateDescriptor]
sectionNameKeyPath:nil
key:self.dataKey];
當(dāng)前的self
需要實現(xiàn)GFDataSourceDelegate
協(xié)議,當(dāng)數(shù)據(jù)庫中滿足查詢條件的數(shù)據(jù)有變動時戚啥,self
會收到協(xié)議方法調(diào)用奋单,你如果是在UITableViewController 中注冊了監(jiān)聽,則需要添加如下代碼:
#pragma mark - GFDataSourceDelegate
- (void)dataSource:(id<GFDataSource>)dataSource willChangeContentForKey:(NSString *)key {
[self.tableView beginUpdates];
}
- (void)dataSource:(id<GFDataSource>)dataSource didChangeContentForKey:(NSString *)key {
[self.tableView endUpdates];
}
- (void)dataSource:(id<GFDataSource>)dataSource
didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type
forKey:(nullable NSString *)key {
switch (type) {
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationNone];
break;
default:
break;
}
}
- (void)dataSource:(id<GFDataSource>)dataSource
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
forKey:(nullable NSString *)key {
switch (type) {
case NSFetchedResultsChangeUpdate:
[self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:newIndexPath];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
}
}
本Data source 支持多個查詢條件猫十,只需要用不同的data key來區(qū)分览濒,比如在示例demo中有如下查詢:
self.dataSource = [DataSource sharedClient];
self.boxDataKey = @"boxData";
self.itemDataKey = @"itemData";
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO];
[self.dataSource registerDelegate:self
entity:[BoxEntity entityName]
predicate:nil
sortDescriptors:@[dateDescriptor]
sectionNameKeyPath:nil
key:self.boxDataKey];
[self.dataSource registerDelegate:self
entity:[ItemEntity entityName]
predicate:nil
sortDescriptors:@[dateDescriptor]
sectionNameKeyPath:nil
key:self.itemDataKey];
數(shù)據(jù)增、刪拖云、改###
因數(shù)據(jù)的修改與界面無關(guān)贷笛,也與線程無關(guān),所以任何地方如果需要增宙项、刪乏苦、改數(shù)據(jù),直接用[MyDataSource sharedClient]
來操作便可尤筐,比如:
[[MyDataSource sharedClient] addObject:data];
修改和刪除都類似汇荐,可以看demo中具體實現(xiàn)。
最后##
本地數(shù)據(jù)庫存儲數(shù)據(jù)盆繁,已經(jīng)是app 不可或缺的一部分掀淘,我們只需要考慮選用哪一種方案,Core Data 雖然槽點太多油昂,但它是Apple 自家產(chǎn)品革娄,有其天然優(yōu)勢,還能與iCloud 無縫對接冕碟,如果你的項目沒有處理大量數(shù)據(jù)的需求拦惋,還是建議用Core Data,當(dāng)然鸣哀,新起之秀 realm 也是個不錯的選項架忌。
祝好!