一个 NSOperation 子类集合,提供了在后台线程中与 NSManagedObject 一起工作的样板代码。
当前项目由以下3个类组成:
在 iOS 5 中引入 performBlock 和 performBlockAndWait 在 NSManagedObjectContext 之后,可以争论说这些类的重要性已经不那么相关了。然而,虽然 blocks 很棒,基于 block 的方法不提供任何排队、依赖链和取消的范畴,而 FRCoreDataOperation 提供了。
更新时间:2015/1/23 在阅读了 Florian Kugler 的研究之后,我得出结论,将代码恢复到使用“老式”的合并技术,因为它提供了更好的性能,并且允许进口几乎完全不在主线程上进行,假设您传递给 FRCoreDataOperation 的上下文是一个与持久存储协调器链接的私有队列上下文。
FRCoreDataOperation
这个类设计为可以子类化。您的子类可以覆盖 main 以及所有其他 NSOperation 方法。您可以直接在父类中插入您自己的 main 方法,但那样有点傻^_^。
FRCoreDataOperation *op = [[FRCoreDataOperation alloc] initWithManagedObjectContext:<MAIN MANAGED OBJECT CONTEXT>];
[<YOUR NSOperationQueue> addOperation:op];
在您子类的操作中,所有对 NSManagedObjectContext 的请求都应该使用
[self threadContext]
这将返回一个线程安全的 managedObjectContext,该上下文将使用您传入的持久存储协调器作为 managed object。不要在操作之外或您的 NSOperation 的 -(void)start 方法中调用此方法,因为这会破坏它的线程隔离。
假设我想要将我访问过的一些国家导入到我的新酷炫旅行应用中,但由于我是一个环游世界的旅行者,这个列表太大了。我的“旅行导入操作”的 main 方法可能看起来像这样...
-(void) main{
@autorelease{
NSArray *countries = @[
@"Argentina",
@"Australia",
...
@"Wales",
nil
];
for( NSString* country in countries ){
//Destination is a our subclassed NSManagedObject
//We create one for each country, and assign it to thread context
[Destination destinationWithName:country
inContext:[self threadContext]
]
}
//Save the context
if( ![[self threadContext] save:&error] ){
NSLog(@"Save failed %@",error);
}
}
}
如果您的操作将要运行很长一段时间,您可能需要定期检查 isCancelled 来确保需要继续。
FRCoreDataBlockOperation
这个类是针对 CoreData 的 NSBlockOperation 类的版本。您可以为操作分配一个 NSManagedObjectContext 并向操作添加多个要执行的 block。像本地的 NSBlockOperation 一样,您不需要子类化 FRCoreDataBlockOperation 就可以使用它。
FRCoreDataBlockOperation *op = [[FRCoreDataBlockOperation alloc] initWithManagedObjectContext:<MAIN MANAGED OBJECT CONTEXT>];
[op addExecutionBlock:^(NSManagedObjectContext *threadContext){
//Do your work on the supplied NSManagedObjectContext
return NO; //Return YES to save, NO to not save
}];
[<YOUR NSOperationQueue> addOperation:op];
NSManagedObjectContext 在所有执行块之间是共享的,因此您可以在块之间共享状态。
执行块返回值决定是否保存 NSManagedObjectContext。
操作中也包含了一个saveAfterExecution属性,用于决定当所有执行块执行完成后,是否保存NSManagedObjectContext。
completionBlock属性在内部不被使用,因此您可以使用它进行清理。或者,这些块按照它们被添加的顺序执行,因此如果您需要访问任何清理的线程 NSManagedObjectContext,可以使用addExecutionBlock:添加一个清理块。
FRCoreDataExportOperation
此操作接受一个实体名称、可选的谓词和排序顺序,并将所有匹配该描述的对象导出到磁盘。
它们写入磁盘的格式可以自定义。使用FRCSVEntityFormatter将对象的属性导出到CSV文件,并保存在用户的Documents目录中。
该类可以使用而无需子类化。
FRCoreDataExportOperation *op = [[FRCoreDataExportOperation alloc] initWithEntityName:@"Destination"
managedObjectContext:<MAIN CONTEXT>];
//[Optional] Set the name of the output file
[op setFileName:@"output.txt"];
//Set the entity formatter
[op setEntityFormatter:[[FRCSVEntityFormatter alloc] init]];
[<YOUR OPERATION QUEUE> addOperation:op];
//[Optional] Set a completion block to know when the file is complete
[op setCompletionBlock:^{
//Refresh the UI or send a notification
}];
'Entity Formatters'遵循FRCoreDataEntityFormatter协议。需要注意的是,您的自定义实体格式化器将被操作保留,并将在后台线程中调用。
所有操作都符合ARC。!
0.4.0
Jonathan Dalrymple 邮箱 j.dalrymple@example.com twitter 在线
虽然我写了代码,但伟大的Marcus Zara给了我灵感和方向,读他的CoreData书,那很值得!
版权(C) 2012 Jonathan Dalrymple
任何获得本软件及其相关文档文件(以下简称“软件”)副本的人,未经限制地处理软件(包括但不限于使用、复制、修改、合并、发布、分发、特许经营和/或销售软件副本的权利),并允许向软件提供的人这样做,前提是
上述版权声明和本许可声明应包含在所有副本或实质性部分的软件中。
软件按“原样”提供,无论明示或暗示,不包括任何保证,包括但不限于适销性、针对特定目的的适用性和非侵权性。在任何情况下,作者或版权所有者均不对任何索赔、损害或其它责任(无论是基于合同、侵权或其他方式)负责,无论该索赔、损害或其它责任是否源于、基于或与软件或其使用或其它操作有关。