簡體   English   中英

帶有無關托管對象上下文的Google Place Picker的CoreData線程問題

[英]CoreData threading issue with Google Place Picker with unrelated Managed Object Context

對不起,很長的帖子; 但是,我想通過。

我有多個托管對象上下文(moc)和大量代碼,能夠穩定,一致地工作。 除了當前問題。 奇怪的是,moc的地址與我創建的地址都不相同-一個不相關的moc崩潰了,我什至無法訪問。 如果有時間,請繼續閱讀。

簡而言之,我創建了一個新的子moc並將其傳遞給新的視圖控制器。 用戶設置一些值並保存。 子moc被保存,然后是父。 但是,在編輯視圖控制器中,如果用戶選擇顯示Google Place Picker,就像開始顯示窗口一樣,我也會遇到多線程錯誤。 我在iPhone 6 Plus實際設備上收到此錯誤,但在iPhone 6S上卻沒有。 它沒有任何問題。 使用6 Plus,總是會在完全相同的位置崩潰。

我啟用了com.apple.CoreData.ConcurrencyDebug 1

這是創建要編輯的子視圖的主要技巧:

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

這是我調用show map函數的地方:

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

這是Google地方選擇器,每次代碼都在同一地方崩潰,並且我什至在這里都沒有訪問任何上下文(實際上,但是刪除它們並不能解決問題):

// =========================================================================
// 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 beta(8T29o),Swift 2.3,但在Xcode版本7.3.1中看到了相同的行為。

任何指針,不勝感激。

中斷堆棧如下所示。 它不會顯示發生沖突的行。 如果這樣做的話,查找錯誤會容易得多。

CorData多線程違規

編輯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。

快速答案是將保存的-performBlockAndWait:包裝在-performBlockAndWait:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM