带有无关的托管对象的Google Place Picker的CoreData线程问题上下文

问题描述:

很抱歉,然而,我想通过。带有无关的托管对象的Google Place Picker的CoreData线程问题上下文

我有多个托管对象上下文(moc)和一个稳定一致的基本代码。除目前的问题。奇怪的是,moc的地址不是我创建的地址 - 一个无关的moc崩溃,我甚至没有访问。如果您有时间,请阅读。

非常简单地说,我创建一个新的孩子moc并将其传递给新的视图控制器。用户设置一些值并保存它们。孩子moc被保存,然后是父母。但是,在编辑视图控制器中,如果用户选择显示Google Place Picker,就像开始显示窗口一样,我会看到多线程错误。我在iPhone 6 Plus实际设备上遇到此错误,但在iPhone 6S上未收到此错误。它的工作没有任何问题。使用6 Plus时,总会在完全相同的地方崩溃。

我已经启用com.apple.CoreData.ConcurrencyDebug 1

这是创建用于编辑的子视图主要wiew:

// ========================================================================= 
// EventsTableViewController 
class EventsTableViewController: UITableViewController { 
    // ========================================================================= 
    // MARK: - Target Action Methods 
    @IBAction func didTapNewEvent(sender: UIBarButtonItem) { 
     guard let vc = storyboard?.instantiateViewControllerWithIdentifier(EditEventTableViewController.identifier) as? EditEventTableViewController else { DLog("ERROR creating EditEventTableViewController"); return } 

     // create a child context 
     let eventContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) 
     eventContext.parentContext = context 
     eventContext.name = "child_of_mainContext_for_Event" 
     let event = NSEntityDescription.insertNewObjectForEntityForName(Event.entityName, inManagedObjectContext: eventContext) 
     vc.segueObject = event 
     vc.context = eventContext 
     vc.shouldDismiss = true 
     vc.delegate = self 
     let nc = UINavigationController(rootViewController: vc) 
     presentViewController(nc, animated: true, completion: nil) 
    } 
} 

这是属性声明的编辑视图控制器:

// ========================================================================= 
// EditEventTableViewController 
class EditEventTableViewController: UITableViewController { 
    // ========================================================================= 
    // MARK: - Google Place properties 
    private var context: NSManagedObjectContext! 
    private var placePicker: GMSPlacePicker! 
} 

这是我所说的显示地图功能:

// ========================================================================= 
// MARK: - UITableViewDelegate 
extension EditEventTableViewController { 
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     if indexPath == Cell.Location.indexPath { 
      didTapSelectFromMap() 
     } 
    } 
} 

这是谷歌的地方选取器的代码崩溃准确每次在同一地点,我都不在访问任何上下文(实际上,我是,但删除它们没有解决的问题):

// ========================================================================= 
// MARK: - Google Places 
extension EditEventTableViewController { 
    func didTapSelectFromMap() { 
     guard let event = selectedObject as? Event else { DLog("ERROR object is not Event"); return } 
     guard let location = locationManager.location else { 
      DLog("Cannot get location, will try again") 
      locationManager.startUpdatingLocation() 
      return 
     } 

     DLog("current location: \(location)") 

     // create viewport around where the user is 
     let center = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude) 
     let northEast = CLLocationCoordinate2DMake(center.latitude + 0.001, center.longitude + 0.001) 
     let southWest = CLLocationCoordinate2DMake(center.latitude - 0.001, center.longitude - 0.001) 
     let viewport = GMSCoordinateBounds(coordinate: northEast, coordinate: southWest) 
     let config = GMSPlacePickerConfig(viewport: viewport) 

     placePicker = GMSPlacePicker(config: config) 

     placePicker.pickPlaceWithCallback {  // the code crashes here! But I have no idea where the violation occurs. 
      (place, error) in 

     } 
    } 
} 

我将所有内容写入日志,并且日志中的相关信息如下。如您所见,我创建了4个上下文,显示了地址,但错误出现在我未创建的某个MOC上。难道那是因为GooglePlacePicker正在使用它自己的moc,并以某种方式与我的混合:)???

[00059]:CDStack.swift     :parentContext................. :12:41:18 CREATED <NSManagedObjectContext: 0x1741dbe40>: parent 
[00068]:CDStack.swift     :context....................... :12:41:18 CREATED <NSManagedObjectContext: 0x1741dbd50>: main 
[00077]:CDStack.swift     :importContext................. :12:41:18 CREATED <NSManagedObjectContext: 0x1701dd3d0>: import 
[00095]:CDStack.swift     :firebaseContext............... :12:41:21 CREATED <NSManagedObjectContext: 0x1741dc020>: firebase 
[00127]:EditEventTableViewController.s :viewDidLoad()................. :12:43:48 Context: <NSManagedObjectContext: 0x1741de3c0>: child_of_mainContext_for_Event 
[00375]:EditEventTableViewController.s :didTapSelectFromMap()......... :12:43:54 current location: <+78.675603,-93.352320> +/- 1414.00m (speed -1.00 mps/course -1.00) @ 25/09/2016, 12:43:54 Southern European Spring Time 
2016-09-25 12:43:54.630499 App[1504:413029] [error] error: The current thread is not the recognized owner of this NSManagedObjectContext(0x1703c3de0). Illegal access during objectRegisteredForID: 

我使用的Xcode 8.1版测试版(8T29o),雨燕2.3,但看到在Xcode 7.3.1版本相同的行为。

任何指针,非常感谢。

下面显示了断点堆栈。它不显示违规发生在哪一行。如果确实如此,那么追踪该错误将会容易得多。

CorData Multithread Violation

编辑1 - 保存功能

class func save(moc:NSManagedObjectContext) { 
    moc.performBlockAndWait { 
     if moc.hasChanges { 
      do { 
       try moc.save() 
      } catch { 
       DLog("ERROR saving context '\(moc)' - \(error)") 
      } 
     } else { 
      // there are no changes 
     } 
     if let parentContext = moc.parentContext { 
      save(parentContext) 
     } 
    } 
} 

要调用的-[GMSTileDataCache storeCacheableTileDatas:completionHandler:]完成块-[NSManagedObjectContext save:]。这是在后台线程上执行的,我怀疑你正在调用保存在与该后台线程无关的上下文中。

快速回答是将保存在-performBlockAndWait:中的文件保存起来。

+0

事情是我不叫这些功能。这些位于Google Place Picker库中。我有一个名为'CDStack'的单例,用于通过'-performBlockAndWait'递归保存受管对象上下文,如果有父节点的话。我在那里放了一个断点,它永远不会被调用。我开始认为违规是在Google图书馆内部的情况下进行的。这甚至有可能吗?我编辑了代码以显示保存功能。我**从未**保存在其他地方。上面的'didTapSelectFromMap()'是当时正在执行的唯一代码。 – oyalhi

+1

Google代码很容易出现线程错误。我会建议查看该方法的来源,并且如果可能的话,更改它以确认它纠正了该问题。 –

+0

我不认为谷歌公开这些功能。我认为要测试的最好方法是使用Google Place Picker创建一个非常简单的Core Data项目,并调用'pickPlaceWithCallback',这似乎违反了线程。感谢您的意见,我很感激。 – oyalhi