Delete binary core data using a func - swift

I want to delete a specific item in a core data binary data set. I have added all of my code below. I tried to follow what I was doing to save the data which worked but trying to apply it to deleting is not currently working. Do not know how to proceed to solve this. I am getting a runtime error at context delete at the helper class.
BASE CLASS
func deleteImage(imageNo:Int) {
// first check the array bounds
let info = DataBaseHelper.shareInstance.fetchImage()
if info.count > imageNo {
// check if the data is available
if let imageData = info[imageNo].img {
DataBaseHelper.shareInstance.deleteImage(data: imageData)
} else {
// no data
print("data is empty")
}
} else {
// image number is greater than array bounds
print("you are asking out of bounds")
}
}
override func viewDidLoad() {
super.viewDidLoad()
deleteImage(imageNo: 2)}
HELPER CLASS
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func deleteImage(data: Data) {
let imageInstance = Info(context: context)
imageInstance.img = data
do {
try context.delete(data)
print("Image is saved")
} catch {
print(error.localizedDescription)
}
}}
error

What you are doing wrong above is
func deleteImage(data: Data) {
// here you create a new object with context
let imageInstance = Info(context: context)
// assigning data to object img property
imageInstance.img = data
// deleting the unsaved object which cause error
do {
try context.delete(data)
print("Image is saved")
} catch {
// this part will be execute because object is not saved
print(error.localizedDescription)
}
}
So the thing is clear first you should have saved object to delete it otherwise it cause error.
So how to delete a specific object
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// pass the object in parameter it will delete the specific info object from CoreData that you will provide in argument
func deleteInfo(info: Info) {
do {
try context.delete(info)
print("Image is saved")
} catch {
print(error.localizedDescription)
}
}
// if you want to remove image but not the info row/object just assign it nil and save again
func deleteImage(info: Info) {
info.img = nil
do {
try context.save()
print("Image is removed but info still here")
} catch {
print(error.localizedDescription)
}
}
}
this how you delete image
if let info = info[imageNo]{
DataBaseHelper.shareInstance.deleteImage(info: info)
}

Related

Swift coreml: Failed to get the home directory when checking model path

I am using this code for extracting text from image, First time the code runs perfectly after that its start giving this error message [coreml] Failed to get the home directory when checking model path. Here is the code that I am using to extract text form image. This is the same code that I have copied from that I have copied from apple documentation
func requestORC(image: UIImage) {
// guard let cgImage = UIImage(named: "test")?.cgImage else { return }
guard let cgImage = image.cgImage else { return }
// / Create a new image-request handler.
let requestHandler = VNImageRequestHandler(cgImage: cgImage)
// Create a new request to recognize text.
let request = VNRecognizeTextRequest(completionHandler: recognizeTextHandler)
do {
// Perform the text-recognition request.
try requestHandler.perform([request])
} catch {
print("Unable to perform the requests: \(error).")
}
}
func recognizeTextHandler(request: VNRequest, error: Error?) {
guard let observations =
request.results as? [VNRecognizedTextObservation] else {
return
}
let recognizedStrings = observations.compactMap { observation in
// Return the string of the top VNRecognizedText instance.
return observation.topCandidates(1).first?.string
}
// Process the recognized strings.
// print(recognizedStrings)
self.recognizedStrings = recognizedStrings
}

how to save uiimage into core data as pngdata

In my swift code below the goal is to save a uiimage using pngdata into core data. The problem is right now it does not appear to be saving because "test numbers" is not being printed into the debug section. I don't know how to make sure its being save. I am looking to save the image and verify its there.
override func viewDidLoad() {
super.viewDidLoad()
let gwen = UIImage(named: "f.jpeg")
if let imageData = gwen.self?.pngData() {
DataBaseHelper.shareInstance.saveImage(data: imageData)
}
let arr = DataBaseHelper.shareInstance.fetchImage()
print("test number : ",arr)
}
Other Class
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveImage(data: Data) {
let imageInstance = Info(context: context)
imageInstance.img = data
do {
try context.save()
print("Image is saved")
} catch {
print(error.localizedDescription)
}
}
func fetchImage() -> [Info] {
var fetchingImage = [Info]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Info")
do {
fetchingImage = try context.fetch(fetchRequest) as! [Info]
} catch {
print("Error while fetching the image")
}
return fetchingImage
}
}
It is a bad approach to saving image in core data!
For saving heavy documents iOS provides you document directory folder which is fast and efficient to save and retrieve than core data and user defaults.
Core data is an sqlite table which is just light weight properties like strings, numbers and Date etc.
Here is a trick you just save your image in document directory folder of your application which has large space and save the reference/ filename into core data.
Rather than creating data property you should have to create imageName property
import Foundation
import CoreData
extension Info {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Info> {
return NSFetchRequest<Info>(entityName: "Info")
}
#NSManaged public var imageName: String?
}
extension Info : Identifiable {
}
After that add this extension for save and get image from document folder
extension UIImage {
func save(to fileName:String) {
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!;
let fileURL = documentsUrl.appendingPathComponent(fileName)
if let imageData = self.jpegData(compressionQuality: 1) {
try? imageData.write(to: fileURL, options: .atomic)
}
}
convenience init(fileName: String) {
var data = Data()
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!;
let fileURL = documentsUrl.appendingPathComponent(fileName)
do {
let imageData = try Data(contentsOf: fileURL)
data = imageData
} catch {
print(error.localizedDescription)
}
self.init(data: data)!
}
}
then how you can save and retrieve reference in core data and image document folder.
class ViewVC:UIViewController {
var images:[UIImage] = [] {
didSet {
print(images.count)
// reload tableView or collectionView
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func saveImage(image:UIImage,fileName:String) {
image.save(to: fileName)
DataBaseHelper.shareInstance.saveImage(fileName: fileName)
}
func getImage() {
let allInfo = DataBaseHelper.shareInstance.fetchInfo()
for info in allInfo {
if let name = info.imageName {
let image = UIImage(fileName: name)
self.images.append(image)
}
}
}
}
you helper class
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveImage(fileName: String) {
let imageInstance = Info(context: context)
imageInstance.imageName = fileName
do {
try context.save()
print("Image name is saved")
} catch {
print(error.localizedDescription)
}
}
func fetchInfo() -> [Info] {
var fetchingImage = [Info]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Info")
do {
fetchingImage = try context.fetch(fetchRequest) as! [Info]
} catch {
print("Error while fetching the image")
}
return fetchingImage
}
}

how to print a count of the amount of core data binary images

In my swift code below the goal is to print the number of items in the a core data attribute. Right now what is being printed out is not making sense to me. What is being printed out is 413091 and it should be 1. I assume that its printing out a number of how core data binary is saved but it should be 1 photo saved 1 item stored and print just 1.
import UIKit;import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let gwen = UIImage(named: "a.jpeg")
if let imageData = gwen.self?.pngData() {
DataBaseHelper.shareInstance.saveImage(data: imageData)
}
let arr = DataBaseHelper.shareInstance.fetchImage()
let jake = Int()
print("core data number is : ", arr[jake].img!.count)
}
}
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveImage(data: Data) {
let imageInstance = Image(context: context)
imageInstance.img = data
do {
try context.save()
print("Image is saved")
} catch {
print(error.localizedDescription)
}
}
func fetchImage() -> [Image] {
var fetchingImage = [Image]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Image")
do {
fetchingImage = try context.fetch(fetchRequest) as! [Image]
} catch {
print("Error while fetching the image")
}
return fetchingImage
}
}

print all items saved in a core data string1

I want my swift code to print out the strings attributes. Right now when calling the function I am getting a runtime error at context. I just want to print out all of each string entry. I have added the function in question below.
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
let appDelegate = UIApplication.shared.delegate as! AppDelegate //Singlton instance
var context:NSManagedObjectContext!
#objc func pressRight(){
let fetchRequest = NSFetchRequest<Place>(entityName: "Name")
do {
let result = try context.fetch(fetchRequest)
let nameArray = result.map{$0.name}
print(nameArray)
} catch {
print("Could not fetch \(error) ")
}
}
pic
select manual in code gen
then create custom class of place add to your project
You are using the wrong entity name "Name" instead of "Place"
import Foundation
import CoreData
class CoreDataManager {
static let shared = CoreDataManager()
private init() {}
lazy var coreDataStack = CoreDataStack(modelName: "Place")
func allNames() -> [String]? {
let request: NSFetchRequest<Place> = Place.fetchRequest()
do {
// Peform Fetch Request
let places = try coreDataStack.managedContext.fetch(request)
return places.map({$0.name})
} catch {
print("Unable to Fetch Workouts, (\(error))")
}
return nil
}
func allPlaces() -> [Place]? {
let request: NSFetchRequest<Place> = Place.fetchRequest()
do {
// Peform Fetch Request
let places = try coreDataStack.managedContext.fetch(request)
return places
} catch {
print("Unable to Fetch Workouts, (\(error))")
}
return nil
}
}
if you still getting error then before this initialize your context
managedObjectContext/context you force unwrapping it
add this stack class
import Foundation
import CoreData
class CoreDataStack {
private let modelName: String
lazy var managedContext: NSManagedObjectContext = {
return self.storeContainer.viewContext
}()
init(modelName: String) {
self.modelName = modelName
}
private lazy var storeContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: self.modelName)
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
print("Unresolved error \(error), \(error.userInfo)")
}
}
return container
}()
func saveContext() {
guard managedContext.hasChanges else {return}
do{
try managedContext.save()
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}
}
func updateContext() {
do {
try managedContext.save()
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}
}
func clearChange() {
managedContext.rollback()
}
}
then how to use it
in your view controller viewDidLoad() function or any other button tap action you can get your place names like this
override func viewDidLoad() {
super.viewDidLoad()
// here you get all names
let names = CoreDataManager.shared.allNames()
print(names)
let places = CoreDataManager.shared.allPlaces()
print(places)
let namesAgain = places.map({$0.name})
print(namesAgain)
}

Could not save data in CoreData swift

I am trying to save data in CoreData. When the app is running everything is ok. I receive info that data is saved and receive messages that it is fetching correct. But when I close the app data just disappeared somewhere.
When I created the project I do not check Core Data, so I added xcdatamodel, import CoreData everywhere, updated AppDelegate with the correct NSPersistentContainer name (the name is name of my xcdatamodel) also in Project-General-Frameworks added CoreData.framework.
Here is part of saving, fetching, and deleting data. The file is separate from VC. I do not receive any type of errors.
In my VC I just call savedata(), to save the data. It works before the app is closed.
import UIKit
import CoreData
var cgsTeams = [TeamsCoreData]()
func savedata() {
saveTeams { (complete) in
if complete {print("TeamsSaved")}
}
}
func saveTeams(completion: (_ finished: Bool) -> ()) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else {return}
let privateManagedContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateManagedContext.parent = managedContext
for team in teams {
let teamsCoreData = TeamsCoreData(context: privateManagedContext)
teamsCoreData.team = team.name
teamsCoreData.score = Int32(team.score)
teamsCoreData.number = Int32(team.number)
do{
try privateManagedContext.save()
debugPrint("Succesfully saved teamsCoreData")
completion(true)
} catch{
debugPrint("Could not save - \(error)")
completion(false)
}
}
}
func fetchTeams(completion: (_ complete: Bool) -> ()) {
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let fetchRequest = NSFetchRequest<TeamsCoreData>(entityName: "TeamsCoreData")
do {
cgsTeams = try managedContext.fetch(fetchRequest)
print("cgsGameRules fetched")
teams = [team]()
for cgsTeam in cgsTeams {
print("team - \(cgsTeam.team!) added")
teams.append(team(name:cgsTeam.team!, number: Int(cgsTeam.number), score: Int(cgsTeam.score)))
}
if cgsTeams.count > 1{completion(true)} else {completion (false); print("No teams")}
} catch {
debugPrint("Could not fetch: \(error.localizedDescription)")
completion(false)
}
}
func deleteTeams(){
guard let managedContext = appDelegate?.persistentContainer.viewContext else { return }
let fetchRequest = NSFetchRequest<TeamsCoreData>(entityName: "TeamsCoreData")
let objects = try! managedContext.fetch(fetchRequest)
for obj in objects {
managedContext.delete(obj)
}
do {
try managedContext.save()
} catch {
print("error on delete Team")
}
}
When you save changes in Core Data, the context saves only to its parent context. If it doesn't have a parent context, it saves changes to the persistent store file. You're saving changes on privateManagedObjectContext, which is a child context of viewContext. But you're never saving changes on viewContext. So your child context is telling the parent context about the changes, but the parent never saves those changes anywhere.
You need to either (a) save changes on viewContext, or (b) make privateManagedObjectContext its own stand-alone context, not a child context.