7

Im trying to fetch entities from my coredata database of my main app and display them in my apps widget Extention. However the fetch always returns an empty results from my database. Can ayone help me out. Swift 3, ios 10.

  • This is a very broad question with many possible issues. Is there an error message? Is the database empty? Can you show some code? – Jerry Dec 10 '16 at 12:54
  • You have to use a shared directory for App and Extension using "App Groups" (Google it). – shallowThought Dec 10 '16 at 13:47
  • Yes i was able to create app groups for the app but i cannot access the coredata directory for ios 10 API. the ios 9 core Data stack has a method in appdelegate for accessing the documents directory of the database but with the new ios 10 Core data stack that method has been removed and im having a hard time accessing the directory for my core database in order to share the directory between components of my App Groups. Any Help? – Shadrach Mensah Dec 19 '16 at 00:45
  • This answer in working fine: [Answer](https://stackoverflow.com/questions/41684256/accesing-core-data-from-both-container-app-and-extension) – anas.p Sep 24 '17 at 18:39

2 Answers2

7

I solved it. After creating the App Group, I created a subclass of NSPersistentContainer and override the class method defaultDirectory() to return the shared app group directory. Also override the init(name: String, managedObjectModel model: NSManagedObjectModel). Then in the coredata stack you replace the boilerplate persistentcontainer code with a new instance of the PersistentContainer class created.

import UIKit
import CoreData
class PersistentContainer: NSPersistentContainer{
     override class func defaultDirectoryURL() -> URL{
    return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bundleId.SomeApp")!
}

override init(name: String, managedObjectModel model: NSManagedObjectModel) {
    super.init(name: name, managedObjectModel: model)
}
}

Then in the CoreDataStack Code *wherever that maybe, either in the Appdelegate or or its own file. Mine was in its own file named CoredataStack

static var persistentContainer:PersistentContainer = {
    let container = PersistentContainer(name: "SomeApp", managedObjectModel: CoreDataStack.managedObjectModel)
    container.loadPersistentStores(completionHandler: { (storeDescription:NSPersistentStoreDescription, error:Error?) in
        if let error = error as NSError?{
            fatalError("UnResolved error \(error), \(error.userInfo)")
        }
    })

    return container
}()

Hope this helps out

  • hope this helps you out – Shadrach Mensah Feb 25 '17 at 18:53
  • Thanks! Just one more question. Now that the core data stack is saved to the shared app group directory, how do you actually fetch the entities from within the extension? I'm having trouble because my attempted code relies on AppDelegate and the extension does not have one. – Michael Bremerkamp Apr 17 '17 at 18:18
  • 1
    You can consider making Appdelegate.swift file a part of your extensions target member but thats not a good coding practice. A better approach is to move all your coredata methods into a stand alone file and then make that file accessible to both your main app and the extension by making the coredata file a target member for both using the target membership pane. – Shadrach Mensah Apr 17 '17 at 22:34
  • @cod_A would this be a singleton file? Would the app and the extension actually share a NSPersistentContainer, having a common persistentStore, persistentStoreController, and managedObjectContext? – SAHM Apr 25 '17 at 02:15
  • Yes, it is going to be a singleton file and yes the app and extension would share same Core data stores, assuming the purpose of the extension is to display data from the base app. – Shadrach Mensah Apr 26 '17 at 05:33
-1

Today Extension runs in a different process from its containing app, thus do not share sandbox, UserDefaults, or database tabled. That is why you get an empty set when trying to fetch data saved in container, from the widget. If you want the containing app and the widget to share data, you should add to your app the capability "App Group" via the iOS developer portal and give it a shared group identifier string. Next, when you instantiate the FileManager object for the database (or UserDefaults), you must use initWithSuiteName method to, passing in the identifier of the shared group.

Shai Givati
  • 1,106
  • 1
  • 10
  • 24