Search code examples
swiftcore-datansmanagedobjectcontextnsfetchrequestexecutefetchrequest

Why does the raywenderlich code break if you enable the scheme "-com. apple.CoreData.ConcurrencyDebug 1"


This example shows how to extract data asynchronously using coreData. If you run program without scheme "-com. apple.CoreData.ConcurrencyDebug 1" all work, but if you turn on scheme "-com. apple.CoreData.ConcurrencyDebug 1" we get runtime error. Why this happens I don't know

(I'm not violating these terms) From apple doc

Core Data is designed to work in a multithreaded environment. However, not every object under the Core Data framework is thread safe. To use Core Data in a multithreaded environment, ensure that:

Managed object contexts are bound to the thread (queue) that they are associated with upon initialization.

Managed objects retrieved from a context are bound to the same queue that the context is bound to.


Stack Trace

CoreData`+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]:
    0x7fff23a8a65e <+0>: pushq  %rbp
    0x7fff23a8a65f <+1>: movq   %rsp, %rbp
->  0x7fff23a8a662 <+4>: ud2 

override func viewDidLoad() {
    super.viewDidLoad()
    do {
      let batchResult = try coreDataStack.managedContext.execute(batchUpdate) as! NSBatchUpdateResult
      print("Records updated \(batchResult.result!)")
    } catch let error as NSError {
      print("Could not update \(error), \(error.userInfo)")
    }

    let venueFetchRequest: NSFetchRequest<Venue> = Venue.fetchRequest()
    fetchRequest = venueFetchRequest

    asyncFetchRequest = NSAsynchronousFetchRequest<Venue>(fetchRequest: venueFetchRequest) {
      [unowned self] (result: NSAsynchronousFetchResult) in
      guard let venues = result.finalResult else {
        return
      }

      self.venues = venues
      self.tableView.reloadData()
    }

    do {
      guard let asyncFetchRequest = asyncFetchRequest else {
        return
      }
      try coreDataStack.managedContext.execute(asyncFetchRequest)
      // Returns immediately, cancel here if you want
    } catch let error as NSError {
      print("Could not fetch \(error), \(error.userInfo)")
    }
 }


Solution

  • This is a good catch. I wish the answer helped more though.

    I downloaded the code and tried it out, and after messing with it for a bit I'm pretty sure that this is a bug in Apple's frameworks. It looks like the code in the sample project is correct, but the concurrency check flags it anyway. I don't know if this is because the code actually causes a concurrency violation or if there's no violation but the flag is buggy.

    What you're seeing is unfortunately just what happens right now, and it's not fixable in an app-- only Apple can resolve it. It's also a longstanding issue, as you can see from this answer from a few years ago. I suggest filing a bug with Apple.