带有不相关托管对象上下文的Google Place Picker的CoreData线程问题 [英] CoreData threading issue with Google Place Picker with unrelated Managed Object Context

查看:75
本文介绍了带有不相关托管对象上下文的Google Place Picker的CoreData线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉,我的帖子很长;但是,我想通过.

Sorry for the long post; however, I wanted to be through.

我有多个托管对象上下文(moc)和大量代码,能够稳定,一致地工作.除了当前的问题.奇怪的是,moc的地址与我创建的地址都不相同-一个无关的moc崩溃了,我什至无法访问.如果有时间,请继续阅读.

I have multiple Managed Object Contexts (moc) and a substantial code working stable and consistently. Except for the current issue. Weird thing is the address of the moc is none of the ones I created - an unrelated moc is crashing that I am not even accessing. Please read on if you have time.

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

Very simply put, I crate a new child moc and pass it on to the new view controller. User sets some values and saves them. Child moc is saved, then parent. However, in the edit view controller, if the user selects to show the Google Place Picker, just as starting to show the window I get a multithreading error. I get this error on iPhone 6 Plus actual device, but not on iPhone 6S. It works with no problems whatsoever. With 6 Plus, always crashes at exactly the same place.

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

这是创建要编辑的子视图的主要技巧:

This is the main wiew that creates the child view for editing:

// =========================================================================
// 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)
    }
}

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

This is the editing view controller where the properties are declared:

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

这是我调用show map函数的地方:

This is where I call the show map function:

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

这是Google地方选择器,每次代码都在同一地方崩溃,而且我什至在这里都没有访问任何上下文(实际上,但是删除它们并不能解决问题):

This is the google place picker where the code crashes exactly the same spot every time and I am not even accessing any contexts here (I was actually, but deleting them did not solve the problem):

// =========================================================================
// 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,并以某种方式与我的:: ??????

I write everything to log, and the relevant info from the log are below. As you can see, I create 4 contexts, the addresses are shown, but the error is on some MOC that I have not created. Could it be that, GooglePlacePicker is using a moc of its own, and somehow getting mixed with mine :)???

[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:

我正在使用Swift 2.3的Xcode 8.1 beta(8T29o),但在Xcode 7.3.1中看到了相同的行为.

I am using Xcode Version 8.1 beta (8T29o), Swift 2.3 but saw the same behavior with Xcode Version 7.3.1.

任何指针都将不胜感激.

Any pointers are greatly appreciated.

中断堆栈如下所示.它不会显示发生冲突的行.如果这样做的话,查找该错误会容易得多.

The stack at break is shown below. It does not show which line the violation occurs. If it did, it would have been a lot easier to track down the bug.

编辑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:].那是在后台线程上执行的,我怀疑您正在与该后台线程无关的上下文中调用save.

You are calling -[NSManagedObjectContext save:] in the -[GMSTileDataCache storeCacheableTileDatas:completionHandler:] completion block. That is being executed on a background thread and I suspect you are calling save on a context that is not associated with that background thread.

快速答案是将保存的内容包装在-performBlockAndWait:中.

Quick answer is to wrap that save in a -performBlockAndWait:.

这篇关于带有不相关托管对象上下文的Google Place Picker的CoreData线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆