Share CoreData between App and Share Extension using Framework

Posted By : Aditya Kumar Sharma | 17-May-2016

Its not easy to share data from our app to an Extension, so I would like to share some steps for sharing Coredata with Share Extension :

  • For passing data from our project to share extension we have to create Framework, so for creating framework go to - File> New> Target> Framework & Library> Cocoa Touch Framework.

  • Then create a Swift file in this framework folder naming it DataAccess.swift .Remove core data code from app delegate and paste it in DataAccess.swift file which may look like this:
import UIKit
import CoreData

class DataAccess: NSObject {
    
    public class var shared: DataAccess {
        struct Static {
            static let instance: DataAccess = DataAccess()
        }
        return Static.instance
    }
    
    //---- Fetch data from Database
    public func fetchFriendsList() -> [AnyObject] {
        var dataToReturn = [AnyObject]()
        var data = Dictionary < String , AnyObject >()
        
        //        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        let managedContext = DataAccess.shared.managedObjectContext
        let fetchRequest = NSFetchRequest(entityName:"Friends")
        var error: NSError?
        
        do{
            let fetchedResults =
            try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
            
            if let results = fetchedResults {
                print("Data Count : \(results.count)")
                for var index = 0; index < results.count; index++ {
                    let match = results[index] as NSManagedObject
                    data = ["id" : match.valueForKey("id") as! String,
                        "name" : match.valueForKey("name") as! String,
                        "phoneNumber" : match.valueForKey("phoneNumber") as! String,
                        "publishTopic" : match.valueForKey("publishTopic") as! String,
                        "subscribeTopic" : match.valueForKey("subscribeTopic") as! String,
                        "imageUrl" : match.valueForKey("imageUrl") as! String,
                    ]
                    dataToReturn.append(data)
                }
            } else {
                print("Could not fetch \(error), \(error!.userInfo)")
            }
        } catch let error1 as NSError {
            error = error1
            print("Could not fetch \(error),\(error!.userInfo)")
        }
        
        return dataToReturn
    }
    
    // MARK: - Core Data stack
    
    public lazy var managedObjectModel: NSManagedObjectModel = {
        // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
        let modelURL = NSBundle.mainBundle().URLForResource("WeOne", withExtension: "momd")!
        return NSManagedObjectModel(contentsOfURL: modelURL)!
    }()
    
    public lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
        
        let  containerPath = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.weone.shareExtension")?.path
        let sqlitePath = NSString(format: "%@%@", containerPath!,"/WeOne")
        let url = NSURL(fileURLWithPath: sqlitePath as String)
        
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        var failureReason = "There was an error creating or loading the application's saved data."
        do {
            try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: [NSMigratePersistentStoresAutomaticallyOption: true,
                NSInferMappingModelAutomaticallyOption: true] )//nil)
        } catch {
            // Report any error we got.
            var dict = [String: AnyObject]()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = failureReason
            
            dict[NSUnderlyingErrorKey] = error as NSError
            let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
            // Replace this with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            print("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
            abort()
        }
        
        return coordinator
    }()
    
    public lazy var managedObjectContext: NSManagedObjectContext = {
        // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
        let coordinator = self.persistentStoreCoordinator
        var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        managedObjectContext.persistentStoreCoordinator = coordinator
        return managedObjectContext
    }()
    
    // MARK: - Core Data Saving support
    
    func saveContext () {
        if managedObjectContext.hasChanges {
            do {
                try managedObjectContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                print("Unresolved error \(nserror), \(nserror.userInfo)")
                abort()
            }
        }
    }
    
} 

In this we made all func public so that we can access them from other places within the app. We have also created a singleton instances through which we could access the func from the app. We must have used App delegate sharedinstance to store values in coredata , which should be now replace by:

       DataAccess.shared.saveContext()
 
  • One more thing we have to keep in notice that we have make access the DataAccess.swift file in whole project for that we have to grant permission in Target membership. For that click on DataAccess file and then see in attribute inspector there would be Target Membership class. Now click tick on the Project file and Share extension file:

By doing this we can access the DataAccess shared instance from anywhere in the project.

  • Now we have to create App groups for createing it go to: Project Target > Capabilities > App groups . Switch on the App groups and tick the group identifier. If there no group identifier present then we can add them by clicking + and then we have to select same group identifier in ShareExtension file App Group

  • Also notice persistentStoreCoordinator call in DataAccess that  there are some changes, here containerPath is added for App group 
        let  containerPath = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.weone.shareExtension")?.path
        let sqlitePath = NSString(format: "%@%@", containerPath!,"/WeOne")
        let url = NSURL(fileURLWithPath: sqlitePath as String)
         

If we have to pass some values from our app to share extension, Then we have to store those values in UserDefaults which can be done like this:

        var defaults = NSUserDefaults(suiteName: "group.weone.shareExtension")
        defaults?.setObject(textToShare, forKey: "textToShare")
        defaults?.synchronize()
 

For retreiving values in share extension we have to use follwing code :

       let defaults = NSUserDefaults(suiteName: "group.weone.shareExtension")
        defaults?.synchronize()
        let restoreTextValue = defaults!.stringForKey("textToShare")
 

restoreTextValue can be used for the value fetched.

 

Thanks

About Author

Author Image
Aditya Kumar Sharma

Aditya is a bright iOS developer, have knowledge of objective C, swift, swift 3, JSON, Core data and iPhone development. Apart from that he loves to travel and explore new things.

Request for Proposal

Name is required

Comment is required

Sending message..