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
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
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.