When saving to CoreData from Today Extension, Data only accesable from Widget - NOT from Main Application

I’m writing an Application for iOS with Swift 3.

In my Main iOS App I’m using an NSFetchedResultsController to show saved items as an TableView.
It’s (of course) possible to add new items from another ViewController.
→ Thats all working really awesome.

So I thought it would be great if I could add an new item really fast from an TodayWidget.

What I did:

  1. Created an SharedCode Framework and added AppGroup to my Main App and the Today Widget.

  2. Moved my CoreDataStack.swift Class, the .xcdatamodeled and my Item+CoreDataClass.swift and Item+CoreDataProperties.swift files to my SharedCode Framework.

  3. Sublcassed NSPersistentContainer to addforSecurityApplicationGroupIdentifier for my appGroupID

  4. Rewrote my CoreData code in my ViewController to use the created CoreDataStack.shared.managedContext

  5. Testing. AWESOME. My NSFetchedResultsController is working, and adding new Items works as expected. Nice. → moveing on.

  6. In my Today Widget I’m using an simple NSFetchRequest to get the last entered Item from CoreData. Works perfectly!

  7. Added Buttons to modify the data and saving it to CoreData. Here I’m also using CoreDataStack.shared.managedContext and CoreDataStack.shared.save()

  8. Automatically reloading my Data AND?! AWESOME. All working very nice. Data is saved and new data is shown in the Today Extension. Also when I count the results from my NSFetchRequest the number of Items is increased.

NOW TO MY PROBLEM:

All the data that I’m adding through the Extension is not showing in my main iOS App.
There when I’m fetching the Items from CoreData there are only the ones showing that I created in the main app. -.-

I have no Idea whats going wrong.
It’s like I have two different CoreDataStores.
Also after I once added an Item trough the Widget - the Widget does not fetch an Item from the main App. Only the last one entered from the Widget.

- Here is my Code:

CoreDataStack.swift

public class CoreDataStack {
    
    public static let shared = CoreDataStack()
    public var errorHandler: (Error) -> Void = {_ in }
    
    //#1
    lazy var persistentContainer: PersistentContainer = {

        let container = PersistentContainer(name: ServiceConsts.modelName)
        var persistentStoreDescriptions: NSPersistentStoreDescription
        
        let storeUrl =  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: ServiceConsts.appGroupID)!.appendingPathComponent("\(ServiceConsts.modelName).sqlite")
        
        let description = NSPersistentStoreDescription()
        description.shouldInferMappingModelAutomatically = true
        description.shouldMigrateStoreAutomatically = true
        description.url = storeUrl
        
        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url:  FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: ServiceConsts.appGroupID)!.appendingPathComponent("\(ServiceConsts.modelName).sqlite"))]
        
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container 
    }()
    
    //#2
    public lazy var managedContext: NSManagedObjectContext = {
        return self.persistentContainer.viewContext
    }()
    
    //#3
    // Optional
    public lazy var backgroundContext: NSManagedObjectContext = {
        return self.persistentContainer.newBackgroundContext()
    }()
    
    //#4
    public func performForegroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
        self.managedContext.perform {
            block(self.managedContext)
        }
    }
    
    //#5
    public func performBackgroundTask(_ block: @escaping (NSManagedObjectContext) -> Void) {
        self.persistentContainer.performBackgroundTask(block)
    }
    
    //#6
    public func saveContext () {
        guard managedContext.hasChanges else { return }
        do {
            try managedContext.save()
        } catch let error as NSError {
            print("Unresolved error \(error), \(error.userInfo)")
        }
    }
}

PersistentContainer.swift

class PersistentContainer: NSPersistentContainer {
    internal override class func defaultDirectoryURL() -> URL {
        var url = super.defaultDirectoryURL()
        if let newURL =
            FileManager.default.containerURL(
                forSecurityApplicationGroupIdentifier: ServiceConsts.appGroupID) {
            url = newURL
        }
        return url
    }
}

Can anyone help?
I have really no idea what I’m doing wrong.

Would be so awesome if anyone can give me a tip :slight_smile:

Thanks <3

@lks. Thanks very much for your question, and my apologies in the delayed reply!

I honestly would make sure that you’re working with the same Managed Object Context when saving data, and then confirm that you are calling the SAVE function on this reference of the MOC. This would be my first thought in considering your problem. It’s much easier to debug smaller blocks of code, and since nothing is crashing, It’s very difficult for me to see what is going on behind the scenes. My other suggestion is to confirm that data is indeed being stored in your extension by tracing through your code step by step. I apologize for not being able to offer more, but this is what I can think of off the top of my head.

I hope this helps :slight_smile:

All the best!