ASJCoreDataOperation 1.3

ASJCoreDataOperation 1.3

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2022年2月

Sudeep维护。



  • Sudeep

ASJCoreDataOperation

将并发/多线程添加到 CoreData 不是非常直接和明显。主要问题是与 NSManagedObjectContext 有关,它是线程不安全的。在 AppDelegate 中创建的默认一个是创建在主线程上的

Swift

var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

Objective-C

NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

使用 AppDelegate 的管理对象上下文的主要缺点是,每当进行保存、检索或删除操作时,主线程/UI 都会被阻塞。如果您正在进行小型操作,这可能不会引起注意。但面对大型的操作,它将造成问题。

解决方案是在后台执行此类 CoreData 操作,只有在您需要进行任何 UI 变更,比如说重新加载表格时,才在主队列上调用 reloadData

安装

CocoaPods是安装此库的首选方式。将以下命令添加到您的Podfile

Swift

pod 'ASJCoreDataOperation'

Objective-C

pod 'ASJCoreDataOperation/Obj-C'

背景

  • 键: NSManagedObjectContext = moc

并发选项

有三种并发类型

  • NSConfinementConcurrencyType(从iOS 9.0开始已标记为弃用)
  • NSPrivateQueueConcurrencyType
  • NSMainQueueConcurrencyType

您不应再使用NSConfinementConcurrencyType,因为它已经过时,并且苹果公司不推荐使用。 NSPrivateQueueConcurrencyType在后台线程上创建一个moc,而NSMainQueueConcurrencyType则在主线程上创建一个。我们感兴趣的是NSPrivateQueueConcurrencyType

创建NSManagedObjectContext

您可以创建任意数量的 moc。在保存过程中,它必须经过一个 NSPersistentStoreCoordinator 向 sqlite 文件写入数据。您可以使用在 AppDelegate 中实现的那个,或者提供自己的。只需确保无论您的应用程序具有哪种类型的存储 NSSQLiteStoreTypeNSXMLStoreTypeNSBinaryStoreTypeNSInMemoryStoreType,协调对象都必须绑定到相同的目的地。

Swift

var privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateMoc.persistentStoreCoordinator = appDelegatesPersistentStoreCoordinator;

Objective-C

NSManagedObjectContext *privateMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
privateMoc.persistentStoreCoordinator = appDelegatesPersistentStoreCoordinator;

moc 的两种方法,分别是 performBlock:(void (^)(void))blockperformBlockAndWait:(void (^)(void))block。在任何这些块中编写的代码都 保证 在创建 moc 的同一队列上执行。您必须在其中一个方法中编写您的 CoreData 逻辑。两者的区别在于,performBlockAndWait: 将在操作完成后阻塞队列。

在私有队列上保存

当在私有 moc 上发生 save 操作时,数据将被写入 sqlite 文件,但主队列将不会收到通知。如果您在主队列上设置了一个 NSFetchedResultsController,控制将 不会 到达其代理方法。然而,如果 CoreData 操作和 NSFetchedResultsController 使用相同的 moc,则它将工作。

如果您需要主队列通知到私有上下文中所做的任何更改,您需要从私有 moc 合并那些更改到主 moc。为此,您必须在私有 moc 上开始监听 NSManagedObjectContextDidSaveNotification

Swift

NotificationCenter.default.addObserver(self, selector: #selector(contextDidSave(note:)), name: .NSManagedObjectContextDidSave, object: privateMoc)

Objective-C

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:privateMoc];

contextDidSave: 中,我们需要将私有 moc 的更改合并到主 moc 中。您必须使用 mocperformBlock:performBlockAndWait: 方法,以确保合并在正确的线程上发生。

Swift

func contextDidSave(note: Notification)
{
  mainMoc.perform { () -> Void in
    self.mainMoc.mergeChanges(fromContextDidSave: note)
  }
}

Objective-C

- (void)contextDidSave:(NSNotification *)note
{
	[mainMoc performBlock:^{
		[mainMoc mergeChangesFromContextDidSaveNotification:note];
	}];
}

note 对象包含对持久化对象所做的所有修改的信息。然而,当在两个 moc 之间合并数据时可能会出现问题,并且可能会发生冲突。因此,您必须提供一个 mergePolicy,以便 CoreData 能够了解如何解决它们。

Swift

privateMoc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

Objective-C

privateMoc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
  • 注意:还有另一种并发模式,使用子 moc 和父 moc,它具有更简单的设置,但不太推荐使用,因为它会阻塞主线程。

这个库的功能

ASJCoreDataOperationOperation/NSOperation 的一个子类,它默认提供私有队列支持。此类设计为可以扩展使用,并**必须继承使用**才能正常工作。

Swift

convenience init(privateMoc: NSManagedObjectContext!, mainMoc: NSManagedObjectContext?)

Objective-C

- (instancetype)initWithPrivateMoc:(nullable NSManagedObjectContext *)privateMoc mainMoc:(nullable NSManagedObjectContext *)mainMoc NS_DESIGNATED_INITIALIZER;

这是创建子类实例的建议方法。您可以在两个参数中都传递nil或使用init方法。在这种情况下,将创建一个私有 moc,并使用 AppDelegatemoc 作为 mainMoc。如果您的 AppDelegate 没有拥有 moc 对象,您必须在主队列上提供一个。

Swift

public var privateMoc: NSManagedObjectContext!

Objective-C

@property (readonly, strong, nonatomic) NSManagedObjectContext *privateMoc;

无论私有 moc 以何种方式创建,它都会公开暴露并供您使用,例如绑定 NSFetchedResultsController 并进行异步检索。

Swift

public var saveBlock: (() -> Void)?

Objective-C

@property (copy) SaveBlock saveBlock;

当保存操作完成时触发的一个代码块。

Swift

public func coreDataOperation()

Objective-C

- (void)coreDataOperation;

您需要在子类中重写此方法。您希望执行的任何 CoreData 操作都应该在这里编写。库将确保在此正确线程上调用此方法。

使用方法

Swift

var operationQueue = OperationQueue()
let operation = SomeCoreDataOperationSubclass(privateMoc: somePrivateMoc, mainMoc: nil)
operationQueue.addOperation(operation)

Objective-C

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
SomeCoreDataOperationSubclass *operation = [[SomeCoreDataOperationSubclass alloc] initWithPrivateMoc:somePrivateMoc mainMoc:nil];
[operationQueue addOperation:operation];

一旦将 operation 添加到 operationQueue,它将在后台队列上开始运行。您可以使用 completionBlock 属性来获取操作完成时的事件。

鸣谢

待办事项

  • 完成块,以便在操作完成后得知。
  • 一种在操作中途取消操作的方法。

许可证

ASJCoreDataOperation 在MIT许可证下可用。有关更多信息,请参阅LICENSE文件。