I have the following coredata code
in my view controller i have a button to update a label
the problem is that i should restart the app or hit the update button twice to see the updated label
it seems the database gets updated but not the ui
my coreDataStack:
import Foundation
import CoreData
class CoreDataStack: NSObject {
static let moduleName = "myModel"
static let sharedInstance = CoreDataStack()
/
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource:
CoreDataStack.moduleName, withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var applicationDocumentsDirectory: URL = {
/
return NSPersistentContainer.defaultDirectoryURL()
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel:
self.managedObjectModel)
let persistentStoreURL =
self.applicationDocumentsDirectory.appendingPathComponent(CoreDataStack.mo
duleName + ".sqlite")
do {
/
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: persistentStoreURL,
options: [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: false])
} catch {
fatalError("Persistent store error! \(error)")
}
return coordinator
}()
fileprivate lazy var saveManagedObjectContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
moc.persistentStoreCoordinator = self.persistentStoreCoordinator
return moc
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.parent = self.saveManagedObjectContext
return managedObjectContext
}()
func saveMainContext() {
guard managedObjectContext.hasChanges || saveManagedObjectContext.hasChanges else {
return
}
managedObjectContext.performAndWait() {
do {
print("saved data simple")
try self.managedObjectContext.save()
} catch {
fatalError("Error saving main managed object context! \(error)")
}
}
saveManagedObjectContext.perform() {
do {
print("saved data private context")
try self.saveManagedObjectContext.save()
} catch {
fatalError("Error saving private managed object context! \(error)")
}
}
}
func createCoreDataContainerOnFirstLaunch() {
/
let previouslyLaunched = UserDefaults.standard.bool(forKey: "previouslyLaunchedDb2")
if !previouslyLaunched {
UserDefaults.standard.set(true, forKey: "previouslyLaunchedDb2")
/
let directory = NSPersistentContainer.defaultDirectoryURL()
let url = directory.appendingPathComponent(CoreDataStack.moduleName + ".sqlite")
/
/
let seededDatabaseURL = Bundle.main.url(forResource: CoreDataStack.moduleName, withExtension: "sqlite")!
/
_ = try? FileManager.default.removeItem(at: url)
do {
try FileManager.default.copyItem(at: seededDatabaseURL, to: url)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
/
let seededSHMURL = Bundle.main.url(forResource: CoreDataStack.moduleName, withExtension: "sqlite-shm")!
let shmURL = directory.appendingPathComponent(CoreDataStack.moduleName + ".sqlite-shm")
_ = try? FileManager.default.removeItem(at: shmURL)
do {
try FileManager.default.copyItem(at: seededSHMURL, to: shmURL)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
/
let seededWALURL = Bundle.main.url(forResource: CoreDataStack.moduleName, withExtension: "sqlite-wal")!
let walURL = directory.appendingPathComponent(CoreDataStack.moduleName + ".sqlite-wal")
_ = try? FileManager.default.removeItem(at: walURL)
do {
try FileManager.default.copyItem(at: seededWALURL, to: walURL)
} catch let nserror as NSError {
fatalError("Error: \(nserror.localizedDescription)")
}
print("Seeded Core Data")
}
}
}
my appDelegate:
var coreDataStack = CoreDataStack()
coreDataStack.createCoreDataContainerOnFirstLaunch()
updateDB.updateDatabase(entityName: "myTable")
my view controller:
var coreDataStack = CoreDataStack()
var MatchList = [Matches]()
override func viewDidLoad() {
super.viewDidLoad()
refreshMatches()
}
#objc func updateMatchDetails() {
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
self.MatchList.removeAll()
self.updateDB.updateDatabase(entityName: "Matches")
DispatchQueue.main.async {
self.refreshMatches()
}
}
func updateDatabase(entityName:String){
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: nil).responseJSON{ response in
if let jsonObject = response.result.value, let items = jsonObject as? [[String: Any]] {
/
/
guard let entity = NSEntityDescription.entity(forEntityName: entityName, in:(self.dataStack.mainContext)) else {
fatalError(LoaderError.NoEntityDescription.rawValue)
}
self.dataStack.sync(items, inEntityNamed: entity.name!) { result in
print(result ?? "updated \(entityName)")
}
} else if let error = response.error {
print(error as NSError)
} else {
print(LoaderError.UnknownError)
}
}
}
func refreshMatches(){
do{
let request = NSFetchRequest<Matches>(entityName:"Matches")
let result = try
self.coreDataStack.managedObjectContext.fetch(request)
MatchList = result
if result.count >= 1{
for item in MatchList {
let row = item.display!
if row == "True"{
if let index = result.index(of: item) {
print("index:\(index)")
self.matchStatus.text = "match status: " + item.matchStatus!
self.view.setNeedsLayout()
}
}
}
}
}catch{
print("there was an error")
}
}
#IBAction func update(_ sender: Any) {
updateMatchDetails()
}
Your network operation will complete asynchronously, so refreshMatches is called before updateDatabase has updated Core Data. This means you only get the old data.
You need to call refreshMatches from the completion handler of your data sync operation:
func updateDatabase(entityName:String){
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: nil).responseJSON{ response in
if let jsonObject = response.result.value, let items = jsonObject as? [[String: Any]] {
guard let entity = NSEntityDescription.entity(forEntityName: entityName, in:(self.dataStack.mainContext)) else {
fatalError(LoaderError.NoEntityDescription.rawValue)
}
self.dataStack.sync(items, inEntityNamed: entity.name!) { result in
print(result ?? "updated \(entityName)")
DispatchQueue.main.async {
self.refreshMatches()
}
}
} else if let error = response.error {
print(error as NSError)
} else {
print(LoaderError.UnknownError)
}
}
}
Related
I have the following coredata singleton class
in my appdelegate i try to update the data from json
but in my app when it launches i get different error messages regarding thread
like
Main Thread Checker: UI API called
or observer of NSManagedObjectContextObjectsDidChangeNotification
or Incorrect guard value
What is the problem and what changes should i make for it to work?
thanks
import CoreData
import Foundation
class CoreDataStack {
static let sharedManager = CoreDataStack()
private init() {} // Prevent clients from creating another instance.
//This is the name of your coreData Database
static let modelName = "myDB"
static let FirstLaunchKey = "firstLaunch"
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource: CoreDataStack.modelName, withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var applicationDocumentsDirectory: URL = {
return NSPersistentContainer.defaultDirectoryURL()
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let persistentStoreURL = self.applicationDocumentsDirectory.appendingPathComponent(CoreDataStack.modelName + ".sqlite")
do {
// let dict = [NSSQLitePragmasOption: ["journal_mode":"DELETE"]]
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: persistentStoreURL,
options: [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: false])
} catch {
fatalError("Persistent store error! \(error)")
}
return coordinator
}()
fileprivate lazy var saveManagedObjectContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
moc.persistentStoreCoordinator = self.persistentStoreCoordinator
return moc
}()
#objc lazy var mainObjectContext: NSManagedObjectContext = {
let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.parent = self.saveManagedObjectContext
return managedObjectContext
}()
func saveMainContext() {
guard mainObjectContext.hasChanges || saveManagedObjectContext.hasChanges else {
return
}
mainObjectContext.performAndWait() {
// print("save performAndWait")
do {
try self.mainObjectContext.save()
} catch {
fatalError("Error saving main managed object context! \(error)")
}
}
saveManagedObjectContext.perform() {
// print("save simple")
do {
try self.saveManagedObjectContext.save()
} catch {
fatalError("Error saving private managed object context! \(error)")
}
}
}
func removeDatabaseForVersion(version:String){
let previouslyVersion = UserDefaults.standard.bool(forKey: version)
if !previouslyVersion {
UserDefaults.standard.set(true, forKey: version)
// Default directory where the CoreDataStack will store its files
let directory = NSPersistentContainer.defaultDirectoryURL()
let url = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite")
let shmURL = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite-shm")
let walURL = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite-wal")
_ = try? FileManager.default.removeItem(at: url)
_ = try? FileManager.default.removeItem(at: shmURL)
_ = try? FileManager.default.removeItem(at: walURL)
}
}
}
in my appdelegate:
UpdateDbClass.updateDatabase(entityName: DbTable.VehiclesEntity.rawValue, completionHandler: {
print(" DB updated delegate")
})
in updatedb class:
import UIKit
import Alamofire
import CoreData
enum LoaderError:String{
case
JsonFailed,
PathFailed,
NoEntityDescription,
UnknownError
}
enum DbTable:String{
case
VehiclesEntity,
PhotosEntity,
ModelsEntity,
NewsEntity,
StylesEntity
}
class UpdateDbClass {
static func updateDatabase(entityName:String,completionHandler: #escaping () -> Void){
var url = URL(string: UrlRepository.VehiclesJsonUrl!)!
var table = ""
switch entityName {
case DbTable.VehiclesEntity.rawValue:
table = "Vehicles"
url = URL(string: UrlRepository.VehiclesJsonUrl!)!
case DbTable.PhotosEntity.rawValue:
table = "Photos"
url = URL(string: UrlRepository.PhotosJsonUrl!)!
table = "Styles"
url = Bundle.main.url(forResource: "Styles", withExtension: "json")!
// url = URL(string: UrlRepository.NewsJsonUrl!)!
default:
break
}
let uuid = UUID().uuidString
let parameters: Parameters = [
"id": uuid
]
let queue = DispatchQueue(label: "com.my.test", qos: .background, attributes: .concurrent)
AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: nil).responseJSON(queue:queue){ response in
switch response.result {
case let .success(value):
if let items = value as? [[String: Any]] {
var itemsArray:[Int32] = []
for item in items{
if let id = item["id"] as? Int32{
itemsArray.append(id)
}
}
guard let entity = NSEntityDescription.entity(forEntityName: table, in:(CoreDataStack.sharedManager.mainObjectContext)) else {
fatalError("Could not find entity descriptions!")
}
switch entityName {
case DbTable.StylesEntity.rawValue: //Styles
checkDeletedRecords(jsonItems: itemsArray,table: table)
for item in items{
guard let id = item["id"] as? Int32 else {return}
//Check if not exists
if !CheckIfExists(id: id,table:table){
print("id \(id) does not exist")
//Insert Record
let object = Styles(entity: entity, insertInto: CoreDataStack.sharedManager.mainObjectContext)
object.setValue(item["id"], forKey: "id")
object.setValue(item["style"] as! String, forKey: "style")
object.setValue(item["image"] as! String, forKey: "image")
CoreDataStack.sharedManager.saveMainContext()
}
else{ //Update Record
// print("id \(item["id"]) exists")
do{
let fetchRequest = NSFetchRequest<Styles>(entityName:"Styles")
let predicate = NSPredicate(format: "id == %d",item["id"] as! Int32)
fetchRequest.predicate = predicate
let req = try CoreDataStack.sharedManager.mainObjectContext.fetch(fetchRequest)
let object = req[0] as NSManagedObject
object.setValue(item["style"] as! String, forKey: "style")
object.setValue(item["image"] as! String, forKey: "image")
CoreDataStack.sharedManager.saveMainContext()
}catch{
print("there was an error")
}
completionHandler()
}
}
break;
default:
break
}
}
break
case let .failure(error):
print(error as NSError)
break
}
}
}
}
protocol CoreDataWorkerProtocol {
associatedtype EntityType
}
enum VoidResult {
case success
case failure(NSError)
}
Response json is called on background thread and you are trying to use viewContext in background thread.
You should use perform block if you want to use viewContext in background.
For example like this
AF.request(:).responseJSON(queue:queue){ response in
let mainContext = CoreDataStack.sharedManager.mainObjectContext
mainContext.perform {
guard let entity = NSEntityDescription.entity(forEntityName: table, in: mainContext) else {
fatalError("Could not find entity descriptions!")
}
}
}
I receive a lot of crashes with in the stacktrace "_coordinator_you_never_successfully_opened_the_database_missing_directory" on the main thread. This is reported in Crashlytics as "This NSPersistentStoreCoordinator has no persistent stores (device locked). It cannot perform a save operation."
is "..._missing_directory" the same as description as Crashlytics is giving ?
what could be the cause ?
how should I solve this ?
#objc class PersistenceController : NSObject {
#objc static let shared = PersistenceController()
fileprivate var managedObjectModel: NSManagedObjectModel?
fileprivate var privateObjectContext: NSManagedObjectContext?
fileprivate var name: String = Bundle.main.bundleIdentifier!
fileprivate var storeLocation: NSURL?
#objc var managedObjectContext: NSManagedObjectContext?
#objc var databasePath: String {
if let storeLocation = self.storeLocation, let storeLocationPath = storeLocation.path {
return storeLocationPath
}
return "Could not find database path"
}
#objc func initializeCoreDataModel(name: String?) -> Bool {
if let safeName = name {
self.name = safeName
}
// Check if a context alreay exsist
if (self.managedObjectContext != nil) {
print("Context already exists, no need to create another")
return true
}
// Fetch the Core Data store
if let modelUrl = Bundle.main.url(forResource: self.name + "Datamodel", withExtension: "momd") {
// Create a model from the store
if let mom = NSManagedObjectModel(contentsOf: modelUrl) {
self.managedObjectModel = mom
// Create the object contexts
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: mom)
// Create MainQueue
self.managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
// Create PrivateQueue
self.privateObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
self.privateObjectContext?.persistentStoreCoordinator = coordinator
// Set MainQueue's parent to PrivateQueue - Now we have Persistent Store Coord => Private => Main
self.managedObjectContext?.parent = self.privateObjectContext
// Create the Persistent Store
if let storeURL = self.storeURL() {
if let persistentStoreCoordinator = self.privateObjectContext?.persistentStoreCoordinator {
self.storeLocation = storeURL
let options: [String : Any] = [NSMigratePersistentStoresAutomaticallyOption: true,
NSPersistentStoreFileProtectionKey: FileProtectionType.none,
NSInferMappingModelAutomaticallyOption: true]
do {
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: self.storeLocation as URL?, options: options)
return true
} catch {
CrashlyticsManager.shared.logCoreDataError(error: error as NSError)
}
}
} else {
print("Could not create document url")
}
} else {
print("Could not create model from core data store")
}
} else {
print("Could not find core data store")
}
return false
}
#objc func save() {
guard let privateContext = self.privateObjectContext, let managedContext = self.managedObjectContext else {
return
}
if (!privateContext.hasChanges && !managedContext.hasChanges) {
return
}
if !UIApplication.shared.isProtectedDataAvailable {
let userInfo = [NSLocalizedDescriptionKey: "isProtectedDataAvailable = false, cannot save()", "MainThread": Thread.isMainThread ? "true" : "false"]
let nsError = NSError(domain: "CoreData", code: 1001, userInfo: userInfo)
CrashlyticsManager.shared.logCoreDataError(error: nsError)
return
}
managedContext.performAndWait({
do {
try managedContext.save()
privateContext.perform({
do {
try privateContext.save()
} catch {
CrashlyticsManager.shared.logCoreDataError(error: error as NSError)
}
})
} catch {
CrashlyticsManager.shared.logCoreDataError(error: error as NSError)
}
})
}
#objc func detachLocalDatabase() {
save()
if let privateObjectContext = self.privateObjectContext {
privateObjectContext.reset()
}
if let context = self.privateObjectContext, let coordinator = context.persistentStoreCoordinator {
for store in coordinator.persistentStores {
do {
try coordinator.remove(store)
} catch {
print(error)
}
}
}
managedObjectModel = nil
managedObjectContext = nil
privateObjectContext = nil
}
#objc func attachLocalDatabase() -> Bool {
return initializeCoreDataModel(name: "PasNL")
}
static func clearDatabase() {
Coupon.deleteAll()
CardStatus.deleteAll()
Message.deleteAll()
Transaction.deleteAll()
Setting.deleteAll()
}
}
private extension PersistenceController {
func storeURL() -> NSURL? {
let applicationSupportDirectoryPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.applicationSupportDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0]
let applicationPath = (applicationSupportDirectoryPath as NSString).appendingPathComponent(self.name)
let storePath = (applicationPath as NSString).appendingPathComponent("\(self.name).db")
let fileExists = FileManager.default.fileExists(atPath: storePath)
if !fileExists {
do {
try FileManager.default.createDirectory(atPath: applicationPath, withIntermediateDirectories: true, attributes: nil)
} catch {
print(error)
}
}
return NSURL(fileURLWithPath: storePath)
}
}
I want to write class for manage all entity that i have in my application.
there is my code fore managerClass for one custom entity, but I have a problem to set manageObject type in this context.
public func clearEntityContex() {
let fetchRequest: NSFetchRequest<Shop> = Shop.fetchRequest()
if let fetchResult = try? self.stack.mainQueueContext.fetch(fetchRequest){
for user : Shop in fetchResult {
self.stack.mainQueueContext.delete(user as Shop)
}
do {
try stack.mainQueueContext.save()
}
catch {
debugPrint(error.localizedDescription)
}
}
}
//MARK: _fetch Contex
public func fetchsShopEntity() -> [Shop]? {
var shops : [Shop]?
let fetchRequest: NSFetchRequest<Shop> = Shop.fetchRequest()
do {
let fetchResult =
try self.stack.mainQueueContext.fetch(fetchRequest)
if fetchResult.count > 0 {
shops = fetchResult
}
}
catch {
fatalError("Failed to fetch Account: \(error)")
}
return shops
}
//MARK: _save entity
public func saveEntityInModel(entityItem : Shop){
if let entity = NSEntityDescription.entity(forEntityName: "Shop", in: self.stack.mainQueueContext) {
if let contex = NSManagedObject(entity: entity, insertInto: self.stack.mainQueueContext) as? Shop {
contex.packID = entityItem.packID
contex.packName = entityItem.packName
contex.packImage = entityItem.packImage
contex.priceDolar = entityItem.priceDolar
contex.packDescription = entityItem.packDescription
do {
try stack.mainQueueContext.save()
}
catch {
debugPrint(error.localizedDescription)
}
}
}
}
for example i want to write method that can clear any entityContext. but i cant pass manageObject to this method.
public func clearEntityContex(entityObject: NSManagedObject) {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = entityObject.fetchRequest()
if let fetchResult = try? self.stack.mainQueueContext.fetch(fetchRequest){
for entity in fetchResult {
self.stack.mainQueueContext.delete(entity as entityObject)
}
do {
try stack.mainQueueContext.save()
}
catch {
debugPrint(error.localizedDescription)
}
}
}
how can solve pass NSManagedObject to this method?
thanks for all reply
Here's a more generic implementation that we use in our projects.
import CoreData
class ACSwiftCoreData: ACCoreDataPlugin {
let managedObjectModelName: String
let databasePath: URL
init(managedObjectModelName: String, databasePath: URL) {
self.managedObjectModelName = managedObjectModelName
self.databasePath = databasePath
}
// MARK: Managed Object Contexts
private var sharedContext: NSManagedObjectContext?
func getSharedManagedObjectContext() throws -> NSManagedObjectContext {
if let sharedContext = self.sharedContext {
return sharedContext
}
let context = try self.createManagedObjectContext()
self.sharedContext = context
return context
}
func createManagedObjectContext() throws -> NSManagedObjectContext {
let storeCoordinator = try self.getPersistentStoreCoordinator()
let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = storeCoordinator
managedObjectContext.mergePolicy = NSMergePolicy(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
return managedObjectContext
}
// MARK: Creating Entities
func createEntityInSharedContext<EntityType>(_ entityName: String) throws -> EntityType {
let context = try self.getSharedManagedObjectContext()
return try self.createEntity(entityName, context: context)
}
func createEntity<EntityType>(_ entityName: String, context: NSManagedObjectContext) throws -> EntityType {
let entity = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context)
guard let expectedEntity = entity as? EntityType else {
throw self.errorWithMessage("ACSwiftCoreData: Entity for name \(entityName) does not match class \(EntityType.self).")
}
return expectedEntity
}
// MARK: Saving Entity
func saveEntity(_ entity: NSManagedObject) throws {
guard let context = entity.managedObjectContext else {
throw errorWithMessage("ACSwiftCoreData: Cannot save Entity. ManagedObjectContext is missing.")
}
if context.hasChanges {
try context.save()
}
}
// MARK: Delete Entity
func deleteEntity(_ entity: NSManagedObject) throws {
guard let context = entity.managedObjectContext else {
throw errorWithMessage("ACSwiftCoreData: Cannot delete Entity. ManagedObjectContext is missing.")
}
context.delete(entity)
try context.save()
}
// MARK: Fetch Requests
func fetchEntitiesInSharedContext<EntityType: AnyObject>(_ entityName: String, predicate: NSPredicate?) -> [EntityType] {
guard let context = try? self.getSharedManagedObjectContext() else {
return [EntityType]()
}
return self .fetchEntities(entityName, context: context, predicate: predicate)
}
func fetchEntities<EntityType: AnyObject>(_ entityName: String, context: NSManagedObjectContext, predicate: NSPredicate?) -> [EntityType] {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
fetchRequest.predicate = predicate
let results = try? context.fetch(fetchRequest)
guard let resultEntitys = results as? [EntityType] else {
return [EntityType]()
}
return resultEntitys
}
// MARK: Technical Details
private var storeCoordinator: NSPersistentStoreCoordinator?
private func getPersistentStoreCoordinator() throws -> NSPersistentStoreCoordinator {
if let storeCoordinator = self.storeCoordinator {
return storeCoordinator
}
let model = try self.getManagedObjectModel()
let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
var options = [AnyHashable: Any]()
options[NSMigratePersistentStoresAutomaticallyOption] = true
options[NSInferMappingModelAutomaticallyOption] = true
try storeCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: self.databasePath, options: options)
self.storeCoordinator = storeCoordinator
return storeCoordinator
}
private var objectModel: NSManagedObjectModel?
private func getManagedObjectModel() throws -> NSManagedObjectModel {
if let objectModel = self.objectModel {
return objectModel
}
let momName = self.managedObjectModelName
guard let modelUrl = Bundle.main.url(forResource: momName, withExtension:"momd") else {
throw self.errorWithMessage("ACSwiftCoreData: DataModel Url could not be created.")
}
guard let objectModel = NSManagedObjectModel(contentsOf: modelUrl) else {
throw self.errorWithMessage("ACSwiftCoreData: DataModel could not be loaded.")
}
self.objectModel = objectModel
return objectModel
}
// MARK: Error handling
private func errorWithMessage(_ message: String) -> NSError {
let userInfo = [NSLocalizedDescriptionKey: message]
let error = NSError(domain: "com.appcron.accomponents", code: 0, userInfo: userInfo)
return error
}
}
In some project that I made and when I used CoreData, I usually create a Singleton with function to fetch, save and delete a CoreData object.
This is my CoreDataController:
import Foundation
import CoreData
import UIKit
final class CoreDataController {
static let sharedInstances = CoreDataController()
private var context: NSManagedObjectContext
private init(){
let application = UIApplication.shared.delegate as! AppDelegate
self.context = application.persistentContainer.viewContext
}
func loadAll() {
print("Fetch from CoreData")
let fetchRequest: NSFetchRequest<YourEntity> = YourEntity.fetchRequest()
do {
let entityArray = try self.context.fetch(fetchRequest)
guard entityArray.count > 0 else {
print("There aren't element in CoreData "); return}
} catch let error {
print("FetchRequest error")
print(" Print error: \n \(error) \n")
}
}
func save(entityToSave: String, item: String){
let entity = NSEntityDescription.entity(forEntityName: entityToSave, in: self.context)
let newItem = YourEntity(entity: entity!, insertInto: self.context)
newItem.name = item
do {
try self.context.save()
} catch let error {
print("Problem with \(newItem)")
print(" Print error: \n \(error) \n")
}
print("Element \(newItem) saved in CoreData")
}
func loadFromName(entityName:String, name: String) -> Any {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
request.returnsObjectsAsFaults = false
let predicate = NSPredicate(format: "yourEntityAttribute = %#", yourEntityAttribute)
request.predicate = predicate
let items = self.loadFromFetchRequest(request: request)
return items[0]
}
private func loadFromFetchRequest(request: NSFetchRequest<NSFetchRequestResult>) -> [Any] {
var array = [Any]()
do {
array = try self.context.fetch(request)
guard array.count > 0 else {print("There aren't element in CoreData"); return []}
for item in array {
print("Item: \(item)")
}
} catch let error {
print("FetchRequest Error")
print(" Print Error: \n \(error) \n")
}
return array
}
func delete(entityName: String, name: String) {
let item = self.loadFromName(entityName: entityName, name: name)
self.context.delete(item as! NSManagedObject)
do {
try self.context.save()
} catch let error {
print("Deleting problem")
print("Print Error: \n \(error) \n")
}
}
func loadData(entity: String) -> [YourEntity] {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
fetchRequest.returnsObjectsAsFaults = false
var data = [YourEntity]()
do {
data = try self.context.fetch(fetchRequest) as! [YourEntity]
} catch let error {
print("Print Error: \n \(error) \n")
}
return data
}
}
When you have to call, just write:
CoreDataController.sharedInstances.save(entityToSave: "Profile", item: textfield.text!)
or other functions!!!
I hope this is useful for you.
For use this Class with every Entity you can write like that:
let entity = NSEntityDescription.entity(forEntityName: entityToSave, in: self.context)
let newItem: Any
switch entityToSave {
case "YourEntity":
newItem = YourEntity(entity: entity!, insertInto: self.context)
(newItem as! YourEntity).entityAttribute = firstItem
(newItem as! YourEntity).entityAttribute = secondItem
case "YourEntity2":
newItem = YourEntity2(entity: entity!, insertInto: self.context)
(newItem as! YourEntity2).entityAttribute = firstItem
(newItem as! YourEntity2).entityAttribute = secondItem
case "YourEntity3":
newItem = YourEntity3(entity: entity!, insertInto: self.context)
(newItem as! YourEntity3).entityAttribute = firstItem
(newItem as! YourEntity3).entityAttribute = secondItem
case "YourEntity4":
newItem = YourEntity4(entity: entity!, insertInto: self.context)
(newItem as! YourEntity4).entityAttribute = firstItem
(newItem as! YourEntity4).entityAttribute = secondItem
default:
fatalError("Error in entityToSave function")
}
do {
try self.context.save()
} catch let error {
print("Problem to save \(newItem)")
print("Print Error: \n \(error) \n")
}
print("Element \(newItem) saved correctly")
}
i am getting the error:
1:EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0*0)
I am new to coding and i am following this video https://www.youtube.com/watch?v=Fv-A8lKn7VY
The code is as follows:
import UIKit
import CoreData
class SwiftCoreDataHelper: NSObject {
class func directoryForDatabaseFilename()->NSString{
return NSHomeDirectory().stringByAppendingString("/Library/Private Documents")
}
class func databaseFilename()->NSString{
return "database.sqlite";
}
class func managedObjectContext()->NSManagedObjectContext{
do { try NSFileManager.defaultManager().createDirectoryAtPath(SwiftCoreDataHelper.directoryForDatabaseFilename() as String, withIntermediateDirectories: true, attributes: nil) }
catch {
print("Error Creating Directory for DB")
}
// NSFileManager.defaultManager().createDirectoryAtPath(SwiftCoreDataHelper.directoryForDatabaseFilename(), withIntermediateDirectories: true, attributes: nil, error: &error)
let path:NSString = "\(SwiftCoreDataHelper.directoryForDatabaseFilename()) + \(SwiftCoreDataHelper.databaseFilename())"
let url:NSURL = NSURL(fileURLWithPath: path as String)
let managedModel:NSManagedObjectModel = NSManagedObjectModel.mergedModelFromBundles(nil)!
let storeCoordinator:NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedModel)
do {
try storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
}
catch {
print("Error: \(error)")
}
let managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = storeCoordinator
return managedObjectContext
}
class func insertManagedObject(className:NSString, managedObjectConect:NSManagedObjectContext)->AnyObject{
let managedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName(className as String, inManagedObjectContext: managedObjectConect) as NSManagedObject
return managedObject
}
class func saveManagedObjectContext(managedObjectContext:NSManagedObjectContext)->Bool{
do {
try managedObjectContext.save()
return true
} catch _ {
return false
}
}
class func fetchEntities(className:NSString, withPredicate predicate:NSPredicate?, managedObjectContext:NSManagedObjectContext)->NSArray{
let fetchRequest:NSFetchRequest = NSFetchRequest()
let entetyDescription:NSEntityDescription = NSEntityDescription.entityForName(className as String, inManagedObjectContext: managedObjectContext)!
fetchRequest.entity = entetyDescription
if (predicate != nil){
fetchRequest.predicate = predicate!
}
fetchRequest.returnsObjectsAsFaults = false
var items = NSArray()
do { items = try managedObjectContext .executeFetchRequest(fetchRequest)
} catch {
print("Fetch Request Failed")
}
return items
}
}
The code where error is generated is:
let entetyDescription:NSEntityDescription = NSEntityDescription.entityForName(className as String, inManagedObjectContext: managedObjectContext)!
I am unable to rectify the error.
entityForName returns an optional value. It probably crashed because you force-unwrap the result of this operation with !
You could use optional binding in this case to test if entityForName actually returns a value:
if let entityDescription = NSEntityDescription.entityForName(className as String, inManagedObjectContext: managedObjectContext) {
// work with entityDescription
} else {
// handle the case in which entityForName returns nil
}
I'm new in using swift and I have a problem to show image in my custom tableview. I take a code from here
this is my coredata
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("test", withExtension: "momd")! <---- The error in here
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
this is my code in controller
func extract_json(jsonData:NSData) {
let json: AnyObject?
do {
json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
} catch {
json = nil
return
}
if let list = json as? NSArray {
for (var i = 0; i < list.count ; i++ ) {
if let data_block = list[i] as? NSDictionary {
TableData.append(datastruct(add: data_block))
}
}
do {
try read()
} catch {}
do_table_refresh()
}
}
func do_table_refresh() {
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
//self.activityView.hidden = true
return
})
}
func load_image(urlString:String, imageview:UIImageView, index:NSInteger) {
let url:NSURL = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
let task = session.downloadTaskWithURL(url) {
(
let location, let response, let error) in
guard let _:NSURL = location, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
let imageData = NSData(contentsOfURL: location!)
dispatch_async(dispatch_get_main_queue(), {
self.TableData[index].image = UIImage(data: imageData!)
self.save(index,image: self.TableData[index].image!)
imageview.image = self.TableData[index].image
return
})
}
task.resume()
}
func read() throws {
do {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Images")
let fetchedResults = try managedContext!.executeFetchRequest(fetchRequest)
for (var i=0; i < fetchedResults.count; i++) {
let single_result = fetchedResults[i]
let index = single_result.valueForKey("index") as! NSInteger
let img: NSData? = single_result.valueForKey("image") as? NSData
TableData[index].image = UIImage(data: img!)
}
} catch {
print("error")
throw ErrorHandler.ErrorFetchingResults
}
}
func save(id:Int,image:UIImage) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Images",
inManagedObjectContext: managedContext)
let options = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
let newImageData = UIImageJPEGRepresentation(image,1)
options.setValue(id, forKey: "index")
options.setValue(newImageData, forKey: "image")
do {
try managedContext.save()
} catch {
print("error")
}
}
in they example it run smoothly but when I try to code it in my project there is an error. It said as
EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
and I can't find any way to fix it.
Please give me some hint how to fix this problem
Thanks, for all the help
I have found my own solution for my problem
The solution is that CoreData I create is xcdatamodel not xcdatamodeld and in my AppDelegate I use momd so I just create a datamodel with xcdatamodeld extension