对于我的生活,我无法弄清楚出了什么问题。我试图找出为什么coredata说我有一个并发问题。在我的tableviewCellForRow方法中,我试图在用户完全向下滚动时加载更多数据。我想在后台上下文中执行此操作,然后保存结果。后台上下文是我的主要上下文的子项(它具有并发类型private)。我正在做:
let backgroundContext = NSManagedObjectContext.mr_newPrivateQueue()
backgroundContext.parent = NSManagedObjectContext.mr_default()
backgroundContext.perform({
self.loadMoreConversationsThenSave(inContext: backgroundContext)
// We want to run any UI updates on the main thread or we have weird crashes/undefined results
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
然后在loadMoreConversations方法中如下所示:
fileprivate func loadMoreConversationsThenSave(inContext context: NSManagedObjectContext) {
let oldestConvoIndex = (conversationsFRC.fetchedObjects?.count ?? 0 ) - 1
if oldestConvoIndex > 0 {
let oldestConvo = conversationsFRC.fetchedObjects?[oldestConvoIndex] as? Conversation
let oldestConvoInContext = context.object(with: (oldestConvo?.objectID)!) as? Conversation
let oldestCallId = oldestConvoInContext?.most_recent_call_id
let oldestCall = FetchRequestHelper.fetch(class: Call.self, withID: oldestCallId, inContext: context) as? Call
if let date = oldestCall?.created_at {
BPDKAPIClient.shared().getConversationsSince(date, isAfterDate: false, completion: { (objects, error) in
if error != nil {
print("ERROR - failed to fetch conversations since date \(error)")
} else {
if objects?.count == 0 {
self.recevedAllCallsFromServer = true
} else {
// Since we're in the callback this is going to be run on the main thread, so we need to wrap
// it in a perform block
context.perform({
Conversation.parseConversationAndCalls(objects, in: context) //points here
do {
try context.save()
} catch {
print("ConversationsTVC: Error saving: \(error)")
}
// We want to run any UI updates on the main thread or we have weird crashes/undefined results
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
})
}
}
}
获取请求帮助程序类创建一个获取请求和一个FRC,然后只使用该ID获取对象并返回它。所有这些都是通过传入的相同上下文完成的。请注意,当API调用getConversationsSince
完成时,我们希望在相同的上下文中执行另一个perform
因为完成该函数是在主线程而不是相同的后台线程上启动的。
断点指向旁边带有注释的行:Conversation.parseConversationAndCalls(objects, in: context)
这就是该方法的样子:
+ (void) parseConversationAndCalls:(NSArray*)objects inContext:(NSManagedObjectContext*)localContext {
for (NSArray *conversationBundle in objects) {
NSArray *conversationsCallData = conversationBundle[1];
NSArray *conversationData = conversationBundle[0];
NSNumber *convoID = [BPDObject scrubbedInteger:conversationData[0]];
Conversation *convo = (Conversation*) [FetchRequestHelper fetchWithClass:Conversation.self withID:convoID inContext:localContext]; //points here
if (convo == nil) {
convo = [Conversation insertInManagedObjectContext:localContext];
}
[convo updateWithValues:conversationData];
Contact *contact = (Contact*) [FetchRequestHelper fetchWithClass:Contact.self withID:convo.contact_id inContext:localContext];
// getCOnversations since date will supply all call data as well
for (NSArray *callData in conversationsCallData) {
NSNumber *callID = [BPDObject scrubbedInteger:callData[1]];
Call *call = (Call*) [FetchRequestHelper fetchWithClass:Call.self withID:callID inContext:localContext];
if (call.objectID.isTemporaryID) {
call = [Call insertInManagedObjectContext:localContext];
}
[call updateWithValues:callData inContext:localContext];
call.contact = contact;
}
}
}
此方法中指向的行是:Conversation *convo = (Conversation*) [FetchRequestHelper fetchWithClass:Conversation.self withID:convoID inContext:localContext];
或任何其他FetchRequestHelper方法。我也不认为它与获取请求助手有关(我已经查看了50次)但是如果你有点好奇的话就是这样:
class FetchRequestHelper: NSObject {
public class func fetchRequest(theClass: BPDObject.Type, predicate: NSPredicate, sortDescriptors: NSArray, inContext context: NSManagedObjectContext) -> NSFetchRequest<NSFetchRequestResult> {
let request = theClass.mr_requestAllSorted(by: "", ascending: true, with: predicate, in: context)
request.sortDescriptors = sortDescriptors as? [NSSortDescriptor]
request.includesPropertyValues = false
request.fetchBatchSize = 20
request.includesPendingChanges = false
return request
}
public class func fetchedResultsController(forRequest request: NSFetchRequest<NSFetchRequestResult>, context: NSManagedObjectContext) -> NSFetchedResultsController<NSFetchRequestResult> {
let fetchedResultController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
public class func fetch(class someClass: BPDObject.Type, withID id: NSNumber!, inContext context: NSManagedObjectContext) -> BPDObject? {
let predicate = NSPredicate(format: "id == %@", id)
let request = FetchRequestHelper.fetchRequest(theClass: someClass, predicate: predicate, sortDescriptors: [], inContext: context)
let frc = FetchRequestHelper.fetchedResultsController(forRequest: request, context: context)
do {
try frc.performFetch()
} catch {
fatalError("Failed to perform fetch from FetchedResultsController: \(error)")
}
return frc.fetchedObjects?.first as? BPDObject
}
}
我怀疑它可能与API调用完成块有关,但我已经在performBlock中包装了下一个操作。可能是什么问题?