I am trying to save additions to a data model using Swift 3. I am getting errors, -[NSTaggedPointerString managedObjectContext]: unrecognized selector sent to instance 0xa00e8808201a0cc8. I have checked the data model and all items referred to in the save are consistent with the data model. My save code is:
let entity = NSEntityDescription.entity(forEntityName: "TransectPlants", in: coreDataStack.context)!
let plantObservation = NSManagedObject(entity: entity, insertInto: coreDataStack.context)
plantObservation.setValue(selectedFamilyName, forKey: "plantFamily")
plantObservation.setValue(selectedSpeciesName, forKey: "plantSpecies")
plantObservation.setValue(transectNameString, forKey: "transectTitle")
do {
try coreDataStack.context.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
The data model is :
[][1
I have used this as my coreDataStack:
import Foundation
import CoreData
class CoreDataStack {
let modelName = "TransectWalkaboutPro"
lazy var context: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(
concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = self.psc
return managedObjectContext
}()
fileprivate lazy var psc: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(
managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory
.appendingPathComponent("TransectWalkaboutPro.sqlite")
do {
let options =
[NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try coordinator.addPersistentStore(
ofType: NSSQLiteStoreType, configurationName: nil, at: url,
options: options)
} catch {
print("Error adding persistent store.")
}
return coordinator
}()
fileprivate lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main
.url(forResource: self.modelName,
withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
fileprivate lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(
for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
func saveContext () {
if context.hasChanges {
do {
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
abort()
}
}
}
}
I cannot see any inconsistencies that would cause the unrecognised selector, what may I be missing?
The line
plantObservation.setValue(transectNameString, forKey: "transectTitle")
causes the error. According to your model the value for key transectTitle must be a managed object instance of Transect rather than a string.
Related
I need to get a NSManagedObject from Core data so I can share it with cloud Kit. I fetch the result based on the entity property and type. Then I try to convert the result into NSManagedObject.
// Fetch NSManagedObject so it can be shared
if let estProfile: NSManagedObject = fetchEntity(uniqueId: self.energyProfileId!, entityType: EstEnergyProfile.self) {
print("fetched NSManagedObject for sharing with cloud kit")
}
//Fetch NSManagedObject given specific property and its type
func fetchEntity (uniqueId: String, entityType: NSManagedObject.Type) -> NSManagedObject?{
var obj: NSManagedObject? = nil
let context = appDelegate.persistentContainer.viewContext
do {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = entityType.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "uniqueId == %#", uniqueId)
let fetchedResults = try context.fetch(fetchRequest)
obj = fetchedResults.first as NSManagedObject
}
catch {
print("Error fetching entity: ", entityType)
}
return obj
}
In the above code at the line
obj = fetchedResults.first as NSManagedObject
I get the error : 'NSFetchRequestResult?' is not convertible to 'NSManagedObject
I don't think I am doing this right. Can someone help fix this code?
I would make the fetch function generic
func fetchEntity<EntityType: NSManagedObject>(_: EntityType.Type, uniqueId: String) -> EntityType? {
let context = appDelegate.persistentContainer.viewContext
do {
let fetchRequest = EntityType.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "uniqueId == %#", uniqueId)
let fetchedResults = try context.fetch(fetchRequest)
return fetchedResults.first as? EntityType
}
catch {
print("Error fetching entity: ", error)
return nil
}
}
Example
let estProfile: NSManagedObject = fetchEntity(EstEnergyProfile.self, uniqueId: self.energyProfileId!)
Given that #FetchRequest does not support dynamic predicates (eg, I could not update the "month" in a calendar and re-query for the events I have scheduled in that month), I am trying to get a manual request to work.
The #FetchRequest already works if I don't try to make a dynamic predicate, so I assume the core data is configured to work correctly.
In my SceneDelegate I have:
guard let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext else {
fatalError("Unable to read managed object context.")
}
let contentView = ContentView().environment(\.managedObjectContext, context)
and in my AppDelegate:
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Transactions")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
If I try doing a manual request in my ContentView like:
let employeesFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Employees")
do {
let employees = try managedObjectContext.fetch(employeesFetch) as! [Employees]
} catch {
fatalError("Failed to fetch employees: \(error)")
}
This fails because `Exception NSException * "+entityForName: nil is not a legal NSPersistentStoreCoordinator for searching for entity name 'Employees'"
What configuration am I missing?
I'm trying to make it work for last couple of days and can't get it working. Its something tiny detail obviously I can't seem to find.
Could you take a look and give me some insights about my code?
I'm trying to update the logView with app savings in the coredata.
Here's the entire code for ViewController and CoreData Handler.
/// fetch controller
lazy var fetchController: NSFetchedResultsController = { () -> NSFetchedResultsController<NSFetchRequestResult> in
let entity = NSEntityDescription.entity(forEntityName: "Logs", in: CoreDataHandler.sharedInstance.backgroundManagedObjectContext)
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
fetchRequest.entity = entity
let nameDescriptor = NSSortDescriptor(key: "name", ascending: false)
fetchRequest.sortDescriptors = [nameDescriptor]
let fetchedController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataHandler.sharedInstance.backgroundManagedObjectContext, sectionNameKeyPath: "duration", cacheName: nil)
fetchedController.delegate = self as? NSFetchedResultsControllerDelegate
return fetchedController
}()
override func viewDidLoad() {
title = "Week Log"
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorColor = UIColor.black
tableView.backgroundColor = UIColor.red
refreshView()
loadNormalState()
loadCoreDataEntities()
}
/**
Refresh the view, reload the tableView.
*/
func refreshView() {
loadCoreDataEntities()
tableView.reloadData()
}
/**
Load history entities from core data. (I'm printing on the console and
be able to see the the fetched data but I can't load it to tableView.)
*/
func loadCoreDataEntities() {
do {
try fetchController.performFetch()
} catch {
print("Error occurred while fetching")
}
}
import Foundation
import CoreData
class CoreDataHandler: NSObject {
/**
Creates a singleton object to be used across the whole app easier
- returns: CoreDataHandler
*/
class var sharedInstance: CoreDataHandler {
struct Static {
static var instance: CoreDataHandler = CoreDataHandler()
}
return Static.instance
}
lazy var backgroundManagedObjectContext: NSManagedObjectContext = {
let backgroundManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
let coordinator = self.persistentStoreCoordinator
backgroundManagedObjectContext.persistentStoreCoordinator = coordinator
return backgroundManagedObjectContext
}()
lazy var objectModel: NSManagedObjectModel = {
let modelPath = Bundle.main.url(forResource: "Model", withExtension: "momd")
let objectModel = NSManagedObjectModel(contentsOf: modelPath!)
return objectModel!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.objectModel)
// Get the paths to the SQLite file
let storeURL = self.applicationDocumentsDirectory().appendingPathComponent("Model.sqlite")
// Define the Core Data version migration options
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
// Attempt to load the persistent store
var error: NSError?
var failureReason = "There was an error creating or loading the application's saved data."
do {
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject
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.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return persistentStoreCoordinator
}()
func applicationDocumentsDirectory() -> NSURL {
return FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).last! as NSURL
}
func saveContext() {
do {
try backgroundManagedObjectContext.save()
} catch {
print("Error while saving the object context")
// Error occured while deleting objects
}
}
You have a data source delegate somewhere. That data source delegate tells the table view how many items there are, and what their contents is. How does it know how many items? That must be stored somewhere.
When the fetch controller is successful, it must modify the data that the data source delegate relies on in some way, and then call reloadData. Are you doing this? Are you doing anything that causes the data source delegate to change the number of items it reports?
And calling loadCoreDataEntities, immediately followed by reloadData, is nonsense. loadCoreDataEntities is asynchronous. By the time you call reloadData, it hasn't loaded any entities yet. realodData is called when loadCoreDataEntities has finished.
Im using swift3. When fetching data from coredata, it returns duplicate values. Using software Datum, i understood that database only contains the original value.
class DatabaseManager: NSObject {
fileprivate static let sharedManager: DatabaseManager = DatabaseManager()
class var shared: DatabaseManager {
return sharedManager
}
/*Returns the ManagedObjectContext*/
var managedObjectContext: NSManagedObjectContext!
var privateManagedObjectContext: NSManagedObjectContext!
fileprivate var completionHandler: ((_ completed: Bool)-> Void)? = nil
override init() {
privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
if let appdelegate = UIApplication.shared.delegate as? AppDelegate {
managedObjectContext = appdelegate.managedObjectContext
privateManagedObjectContext.persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator
}
}
deinit {
managedObjectContext = nil
privateManagedObjectContext = nil
}
}
//Fetching data
func getItem()->[ListItem]{
var objects = [ListItem]()
var uniqueObjects:[ListItem] = [ListItem]()
let sort = NSSortDescriptor(key: "itemName", ascending: false)
let request : NSFetchRequest<ShoppyListItem> = ShoppyListItem.fetchRequest() as NSFetchRequest<ShoppyListItem>
//let predicate = NSPredicate(format:"excludedIDContain = %#","New")
// request.predicate = predicate
request.sortDescriptors = [sort]
do {
if objects.count > 0 {
objects.removeAll()
}
objects = try managedObjectContext?.fetch(request) ?? []
return objects
} catch {
print("Error with request: \(error)")
}
return objects
}
// objects = try managedObjectContext?.fetch(request) ?? [] returns duplicated objects
i got it. Im not mistaken about the count. It was due to concurrency. i was not running fetch on the safe thread of coredata. All i had to do was put the code inside perform block.
managedObjectContext.perform(block).
Got this from stanford ios tutorial named coredata demo. Video time 26:00. The professor explains this.
I am setting up ensembles to sync CoreData to iCloud.
But it crashes on launch:
[NSMapTable cde_strongToStrongObjectsMapTable]: unrecognized selector sent to class 0x10d978c70
2016-08-05 12:48:42.502 Shooters_Journal[30266:751831] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSMapTable cde_strongToStrongObjectsMapTable]: unrecognized selector sent to class 0x10d978c70'
I dont understand what this means. How do I proceed to debug??
I have added my CoreData Stack and Ensembles setup. For the record, the app works very well without setting up ensembles.
In my AppDelegate I have:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// setups
// Setup Ensemble
let modelURL = NSBundle.mainBundle().URLForResource("Myidentifier", withExtension: "momd")
cloudFileSystem = CDEICloudFileSystem(ubiquityContainerIdentifier: nil)
let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CoreData.sqlite")
ensemble = CDEPersistentStoreEnsemble(ensembleIdentifier: "ShotsStore", persistentStoreURL: storeURL, managedObjectModelURL: modelURL!, cloudFileSystem: cloudFileSystem)
ensemble.delegate = self
return true
}
My CoreData stack is the default XCode creates
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("Myidentifier", withExtension: "momd")
return NSManagedObjectModel(contentsOfURL: modelURL!)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let storeUrl = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeUrl, options: 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)
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
The app compiles fine, but on start I get following error:
[NSMapTable cde_strongToStrongObjectsMapTable]: unrecognized selector
sent to class 0x10d978c70
All I now is that the line:
ensemble = CDEPersistentStoreEnsemble(ensembleIdentifier: "ShotsStore", persistentStoreURL: storeURL, managedObjectModelURL: modelURL!, cloudFileSystem: cloudFileSystem)
is causing the crash.
I have no idea if its the persistentStoreURL, managedObjectModelURL or cloudFileSystem that is cousing the error.
I think you forgot the -ObjC step in the README. That will cause all categories to be linked, which is causing the missing symbols error.