iOS 12 Errors: appears to be from a different NSMa

2020-07-17 05:21发布

I started to get the following error when launching my application on iOS 12 simulator. Did anybody face issue like this?

2018-08-11 21:17:44.440144+0300 CafeManager[4633:128874] [error] error: The fetch request's entity 0x600001f6e940 'TablesTable' appears to be from a different NSManagedObjectModel than this context's

I have global constant defined in AppDelegate:

let viewContext = AppDelegate.viewContext

And use it with NSFetchedResultsController for UITableView update, for example:

import UIKit
import CoreData

class HistoryTablesTableViewController: FetchedResultsTableViewController {
    //MARK: variables
    private var fetchedResultsController: NSFetchedResultsController<TablesTable>?
    private var currentTable: TablesTable?
    private var tableNameTextField: UITextField!

    //MARK: system functions for view
    override func viewDidLoad() {
        super.viewDidLoad()
        sideMenu()
        addSyncObserver()
    }
    override func viewWillAppear(_ animated: Bool) {
        updateGUI()
    }

    // MARK: IBOutlets
    @IBOutlet weak var menuButton: UIBarButtonItem!

    // MARK: side menu
    private func sideMenu() {
        if revealViewController() != nil {
            menuButton.target = revealViewController()
            menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
            revealViewController().rearViewRevealWidth = 260

            view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        }
    }

    //MARK: functions for table update
    private func updateGUI () {
        let request : NSFetchRequest<TablesTable> = TablesTable.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "tableName", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))]
        fetchedResultsController = NSFetchedResultsController<TablesTable>(fetchRequest: request, managedObjectContext: viewContext, sectionNameKeyPath: nil, cacheName: nil)
        try? fetchedResultsController?.performFetch()
        tableView.reloadData()
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! HistoryTablesTableViewCell
        if let tablesTable = fetchedResultsController?.object(at: indexPath) {
            cell.tableNameLabel.text = tablesTable.tableName
            cell.cellDelegate = self
            cell.table = tablesTable
        }
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath as IndexPath)
        tableView.deselectRow(at: indexPath as IndexPath, animated: true)
        currentTable = fetchedResultsController?.object(at: indexPath)
        performSegue(withIdentifier: "showTableSessions", sender: cell)
    }

    //MARK: prepare for segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showTableSessions" {
            if let tableSessionsTVC = segue.destination as? TableSessionsTableViewController {
                tableSessionsTVC.title = self.currentTable!.tableName!
                tableSessionsTVC.currentTable = self.currentTable!
            }
        }
    }
}

// MARK: Delegates
extension HistoryTablesTableViewController: HistoryTablesTableViewCellDelegate {
    func didPressTablesCellButton(table: TablesTable) {
        currentTable = table
    }
}

// Common extension for fetchedResultsController
extension HistoryTablesTableViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return fetchedResultsController?.sections?.count ?? 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].numberOfObjects
        }
        else {
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].name
        }
        else {
            return nil
        }
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return fetchedResultsController?.sectionIndexTitles
    }

    override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        return fetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
    }
}

// Observer to check that sync was performed to update GUI
extension HistoryTablesTableViewController {
    private func addSyncObserver () {
        NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: appDelegate.syncDidFinishNotification), object: nil, queue: nil) {
            [weak self] notification in
            DispatchQueue.main.async {
                self?.updateGUI()
            }
        }
    }
}

In the same time it looks like that app works, but had no chance to test everything properly yet.

I use CoreData, Seam3 framework.

I found the only one mention of this error on github, but do not see solution.

3条回答
一纸荒年 Trace。
2楼-- · 2020-07-17 05:52

In my case it was a simple solution, I am using 4 contexts and I had to set their parent to the main context.

var mainManagedContext: NSManagedObjectContext {
    return persistentContainer.viewContext
}

lazy var backgroundQueueContext: NSManagedObjectContext = {
    let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    context.parent = mainManagedContext
    return context
}()

lazy var mainQueueContext: NSManagedObjectContext = {
    let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    context.parent = mainManagedContext
    return context
}()

lazy var alternativeContext: NSManagedObjectContext = {
    let context = persistentContainer.newBackgroundContext()
    return context
}()
查看更多
乱世女痞
3楼-- · 2020-07-17 05:54

I ran into something similar when we created two instances of model even if they are read from the same momd file. My assumption was that if it's read from the same file, they should be the same model, but I guess something has changed internally that no longer treats two instances from read from the same momd file as the same model.

Make sure when you're referencing viewContext it is as shared (same instance) of NSManagedObjectContext and not initializing a new model instance from the file.

I hope this helps.

查看更多
SAY GOODBYE
4楼-- · 2020-07-17 06:02

I had been getting this error with iOS 12 also. This is how I finally fixed it in my project. This is in Objective C, not Swift, but hopefully it will get you going in the right direction.

The code that produced this error looked like this

// in the init code for my object
NSString *pathm = [[NSBundle mainBundle] pathForResource:@"mycoredb" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:pathm];
self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];


// in another method in the object
NSFetchRequest *request = [[NSFetchRequest alloc] init];

NSEntityDescription *entity = [[self.model entitiesByName] objectForKey:@"Model_name"];
[request setEntity:entity];

The issue has something to do with the entity. So I updated my code to reflect the example on this page: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/FetchingObjects.html

Here is how my code looks now

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Model_name"];

no more "appears to be from a different NSManagedObjectModel than this context" error.

查看更多
登录 后发表回答