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!")
}
}
}
Related
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)
}
}
}
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
}
Unfortunately the new Core Data semantics make me crazy. My previous question had a clean code that didn't work because of incorrect auto generation of header files. Now I continue my work with deleting objects.
My code seems to be very simple:
func deleteProfile(withID: Int) {
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
let object = try! context.fetch(fetchRequest)
context.delete(object)
}
I did a "hard" debug with print(object) instead of context.delete(object) and it showed me the right object.
So I need just to delete it.
P.S. there is no deleteObject. Now NSManagedContext has only public func delete(_ sender: AnyObject?)
The result of a fetch is an array of managed objects, in your case
[Event], so you can enumerate the array and delete all matching objects.
Example (using try? instead of try! to avoid a crash in the case
of a fetch error):
if let result = try? context.fetch(fetchRequest) {
for object in result {
context.delete(object)
}
}
do {
try context.save()
} catch {
//Handle error
}
If no matching objects exist then the fetch succeeds, but the resulting
array is empty.
Note: In your code, object has the type [Event] and therefore in
context.delete(object)
the compiler creates a call to the
public func delete(_ sender: AnyObject?)
method of NSObject instead of the expected
public func delete(_ object: NSManagedObject)
method of NSManagedObjectContext. That is why your code compiles
but fails at runtime.
The trick here, it is save context after deleting your objects.
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
let objects = try! context.fetch(fetchRequest)
for obj in objects {
context.delete(obj)
}
do {
try context.save() // <- remember to put this :)
} catch {
// Do something... fatalerror
}
I hope this can help someone.
func deleteRecords() {
let delegate = UIApplication.shared.delegate as! AppDelegate
let context = delegate.persistentContainer.viewContext
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "nameofentity")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print ("There was an error")
}
}
Delete core data objects swift 3
// MARK: Delete Data Records
func deleteRecords() -> Void {
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Person")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Person]
for object in resultData {
moc.delete(object)
}
do {
try moc.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
// MARK: Get Context
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
Swift 4.1, 4.2 and 5.0
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let requestDel = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
requestDel.returnsObjectsAsFaults = false
// If you want to delete data on basis of some condition then you can use NSPredicate
// let predicateDel = NSPredicate(format: "age > %d", argumentArray: [10])
// requestDel.predicate = predicateDel
do {
let arrUsrObj = try context.fetch(requestDel)
for usrObj in arrUsrObj as! [NSManagedObject] { // Fetching Object
context.delete(usrObj) // Deleting Object
}
} catch {
print("Failed")
}
// Saving the Delete operation
do {
try context.save()
} catch {
print("Failed saving")
}
Swift 4 without using string for Entity
let fetchRequest: NSFetchRequest<Profile> = Profile.fetchRequest()
fetchRequest.predicate = Predicate.init(format: "profileID==\(withID)")
do {
let objects = try context.fetch(fetchRequest)
for object in objects {
context.delete(object)
}
try context.save()
} catch _ {
// error handling
}
Delete Core Data Object with query in Swift 5, 4.2
let fetchRequest = NSFetchRequest<Your_Model>(entityName: "Your_Entity_Name")
fetchRequest.predicate = NSPredicate(format: "any your_key == %d", your_value)
hope this will help to someone
Swift 5
Common function for Deleting core data objects for any anity swift 5
func deleteEntityObjectByKeyValue<T>(className: T.Type, key: String, value: Any) -> Bool {
let context = CoreDataStack.sharedStack.mainContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: className.self))
//Search based on data type.I used for Int and String
if let sValue = value as? String {
let predicate = NSPredicate(format: "\(key) == %#", sValue)
fetchRequest.predicate = predicate
} else if let iValue = value as? Int64 {
let predicate = NSPredicate(format: "\(key) == %d", iValue)
fetchRequest.predicate = predicate
}
do {
let result = try context.fetch(fetchRequest)
if result.count != 0 {
if let managedObject = result[0] as? NSManagedObject {
context.delete(managedObject)
do {
try context.save()
return true
}
catch let error {
print(error.localizedDescription)
}
}
}
return false
} catch let error {
print(error.localizedDescription)
}
return false
}
How To Use it:
let isSaved = CoreDataOperations.shared.deleteEntityObjectByKeyValue(className: EmpolyeeData.self, key: "employeeId", value:1234)
If isSaved {
print("Deleted obj Successfully")
}
Swift 4,5
It is useful to delete particular record or all records from entity.
1.Create a NSPersistentContainer and NSManagedObjectContext using below code.
class CoreDataStack: NSObject {
static var sharedStack = CoreDataStack()
private override init() {}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Employee")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let url = storeDescription.url {
print("SQLITE STORE LOCATION: \(url.absoluteString)")
}
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.shouldDeleteInaccessibleFaults = true
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()
private lazy var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
private lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = Bundle.main.url(forResource: "____", withExtension: "____")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
public lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("Employee" + ".sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, 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)")
}
return coordinator
}()
lazy var mainContext: NSManagedObjectContext = {
var managedObjectContext: NSManagedObjectContext?
if #available(iOS 10.0, *){
managedObjectContext = self.persistentContainer.viewContext
managedObjectContext?.mergePolicy = NSMergePolicy.init(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
}
else{
// 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
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext?.persistentStoreCoordinator = coordinator
managedObjectContext?.mergePolicy = NSMergePolicy.init(merge: NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType)
}
return managedObjectContext!
}()
}
2.Common function for Deleting core data all objects for any Entity swift 5
func deleteEntityData(entity : String) {
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try CoreDataStack.sharedStack.mainContext.execute(deleteRequest)
CoreDataStack.sharedStack.saveMainContext()
} catch {
print ("There was an error")
}
}
3.How to use above code.
self.deleteEntityData(entity : "Employee")
4.If you want to delete Particular object from Entity
func deleteEntityObjectByKeyValue<T>(entityName: T.Type, key: String, value: Any) -> Bool {
let context = CoreDataStack.sharedStack.mainContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: entityName.self))
if let sValue = value as? String {
let predicate = NSPredicate(format: "\(key) == %#", sValue)
fetchRequest.predicate = predicate
} else if let iValue = value as? Int64 {
let predicate = NSPredicate(format: "\(key) == %d", iValue)
fetchRequest.predicate = predicate
}
do {
let result = try context.fetch(fetchRequest)
if result.count != 0 {
if let managedObject = result[0] as? NSManagedObject {
context.delete(managedObject)
do {
CoreDataStack.sharedStack.saveMainContext()
return true
}
catch let error {
print(error.localizedDescription)
}
}
}
return false
} catch let error {
print(error.localizedDescription)
}
return false
}
Delete the object from core data
let entity = NSEntityDescription.entity(forEntityName: "Students", in: managedContext)
let request = NSFetchRequest<NSFetchRequestResult>()
request.entity = entity
if let result = try? managedContext.fetch(request) {
for object in result {
managedContext.delete(object as! NSManagedObject)
}
txtName.text = ""
txtPhone.text = ""
txt_Address.text = ""
labelStatus.text = "Deleted"
}
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