save string over saved string in core data - swift

In my swift code below the code saves an item in core data. The goal is to overwrite that item. I am getting a runtime error at
CoreDataHandler.changeName(user: fetchUser!\[indexNumber\], jessica: "jo")
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
I don't know how to wrap in the index number. The goal is it to print judo then jo
import UIKit;import CoreData
class ViewController: UIViewController {
var fetchUser: [UserInfo]? = nil
var indexNumber : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
CoreDataHandler.saveObject2( name: "judo")
getText(textNo: indexNumber)
saveTheItem()
}
#objc func saveTheItem(){
CoreDataHandler.changeName(user: fetchUser![indexNumber], jessica: "jo")
}
func getText(textNo:Int) {
// first check the array bounds
let info = helpText.shareInstance.fetchText()
if info.count > textNo {
if let imageData = info[textNo].name
{
print(imageData)
} else {
// no data
print("data is empty Textss")
}
} else {
// image number is greater than array bounds
print("you are asking out of bounds")
}
}
}
class CoreDataHandler : NSManagedObject {
class func saveObject2( name: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "UserInfo", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(name, forKey: "name")
do{
try context.save()
return true
}
catch {
return false
}
}
private class func getContext() -> NSManagedObjectContext{
let appD = UIApplication.shared.delegate as! AppDelegate
return appD.persistentContainer.viewContext
}
class func changeName(user: UserInfo,jessica : String) -> Bool
{
let context = getContext()
user.name = jessica
print(jessica)
do{
try context.save()
return true
}
catch{
return false
}
}
}
class helpText: UIViewController{
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
static let shareInstance = helpText()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveName(data: String) {
let imageInstance = UserInfo(context: context)
imageInstance.name = data
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
func fetchText() -> [UserInfo] {
var fetchingImage = [UserInfo]()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserInfo")
do {
fetchingImage = try context.fetch(fetchRequest) as! [UserInfo]
} catch {
print("Error while fetching the image")
}
return fetchingImage
}
}

No offense but your code is a mess.
And there is a big misunderstanding. Core Data records are unordered, there is no index. To update a record you have to fetch it by a known attribute, in your example by name, update it and save it back.
This is a simple method to do that. It searches for a record with the given name. If there is one, update the attribute with newName and save the record.
The code assumes that there is a NSManagedObject subclass UserInfo with implemented class method fetchRequest.
func changeName(_ name: String, to newName: String) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request : NSFetchRequest<UserInfo> = UserInfo.fetchRequest()
request.predicate = NSPredicate(format: "name == %#", name)
do {
let records = try context.fetch(request)
guard let foundRecord = records.first else { return }
foundRecord.name = newName
try context.save()
} catch {
print(error)
}
}
Regarding your confusing code:
Create CoreDataHandler as singleton (and it must not be a subclass of NSManagedObject). Move the Core Data related code from AppDelegate and the methods to read and write in this class.

Related

Deleting a binary data image by a instance

In my Swift code below the goal is to delete a binary data by the corresponding var Int. The var Int is called counterImage. My code right now is causing a runtime error of counterImage
'Cannot convert value of type 'Int' to expected argument type 'TheBook''
What can I do to fix this? All the code is right here. You would have to add the images but after that you can just copy and paste the code.
import UIKit;import CoreData
class ViewController: UIViewController {
var counterImage = 1
override func viewDidLoad() {
super.viewDidLoad()
let gwen = UIImage(named: "h")
if let imageData = gwen.self?.pngData() {
helpImage.shareInstance.saveImage(data: imageData)
}
let gwen2 = UIImage(named: "hh")
if let imageData = gwen2.self?.pngData() {
helpImage.shareInstance.saveImage(data: imageData)
}
helpImage.shareInstance.deleteObject(user: counterImage)
}
}
class helpImage: UIViewController{
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
static let shareInstance = helpImage()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveImage(data: Data) {
let imageInstance = TheBook(context: context)
imageInstance.pic = data
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
func deleteObject(user: TheBook) {
let context = helpImage.getContext()
let delete = NSBatchDeleteRequest(fetchRequest: TheBook.fetchRequest())
do {
try context.execute(delete)
} catch {
}
}
}

use helper method to fetch specific attribute from core data

IN my swift 5 code below the goal would be to fetch the first item from core data entity Info attribute username. I am attempting to d that right now I am getting a error at titleLabel.text = String(user![0]) stating
no exact matches in call to initializer
Somehow I know I will need to attach .username somehow but I dont know what to do next at this point.
class ViewController: UIViewController {
var user : [User]? = nil
var titleLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
user = CoredataHandler.fetchObject()
titleLabel.text = String(user![0])
}
}
class CoredataHandler : NSManagedObject {
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
class func saveObject(username: String,password: String,tf: Bool) -> Bool{
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(username, forKey: "username")
managedObject.setValue(password, forKey: "password")
managedObject.setValue(tf, forKey: "tf")
do {
try context.save()
return true
} catch{
return false
}
}
class func fetchObject() -> [User]?
{
let context = getContext()
var user : [User]? = nil
do {
user = try context.fetch(User.fetchRequest())
return user
} catch {
return user
}
}
}

fetch core data string by int in a parameter function

In my swift code I attempted to fetch core data string using a int. I have 2 classes my base class and my helper class. In my base class that is where the func attempting to fetch the string. That func has a error message at fetchImageTxt.text = String(data: imageData) stating Missing argument for parameter 'encoding' in call. Don't know how to resolve it.
BASE CLASS
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var fetchImageTxt = UITextField()
func getT(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 {
fetchImageTxt.text = String(data: imageData)
} else {
// no data
print("data is empty")
}
} else {
// image number is greater than array bounds
print("you are asking out of bounds")
}
}
}
HELPER CLASS
class DataBaseHelper {
static let shareInstance = DataBaseHelper()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
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
}
}
coreDataAttributes

Use core data index to fetch a specific item from core data

My swift code below when loaded places 3 items in the core data entity named "UserName". When the user enters a number into textfield enterT I want the label labelName to display it. So when the user enters 1 the label should display jessica biel because Jesical Biel is the first name entered. Someone stated the suggestion below to solve this problem. I dont know exactly how to do this.I have added a gif below.
Convert the entered number to Int. If this succeeds pass the integer to joke and fetch the record matching the idx attribute.
https://github.com/redrock34/index-fetch
import UIKit
import CoreData
class ViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var labelName : UILabel!
#IBOutlet var enterT : UITextField!
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
openDatabse()
fetchData()
enterT.delegate = self
}
func textFieldDidEndEditing(_ textField: UITextField) {
guard let index = Int(textField.text!) else {
// display an alert about invalid text
return
}
joke(at: index - 1)
}
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
labelName.text = user.username
}
} catch {
print("Could not fetch \(error) ")
}
}
func openDatabse()
{
let names = ["kim kardashian", "jessica biel", "Hailey Rienhart"]
for i in 0..<names.count {
let newUser = Users(context: context)
newUser.username = names[i]
newUser.idx = Int32(i + 1)
}
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
}
func fetchData()
{
print("Fetching Data..")
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
let userName = data.value(forKey: "username") as! String
print("User Name is : "+userName)
}
} catch {
print("Fetching data Failed")
}
}}
Of course you have to assign values to the idx attribute and you have to assign the result of the fetch to the label.
First replace
let appDelegate = UIApplication.shared.delegate as! AppDelegate //Singlton instanc
var context:NSManagedObjectContext!
with
lazy var context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
Then replace both openDatabse and saveData with
func openDatabse()
{
let names = ["kim kardashian", "jessica biel", "Hailey Rienhart"]
for i in 0..<names.count {
let newUser = Users(context: context)
newUser.name = names[i]
newUser.idx = Int32(i + 1)
}
print("Storing Data..")
do {
try context.save()
} catch {
print("Storing data Failed", error)
}
}
Finally add a line in joke to display the value
func joke(at index : Int) {
let fetchRequest = NSFetchRequest<Users>(entityName: "Users")
fetchRequest.predicate = NSPredicate(format: "idx == %d", Int32(index))
do {
if let user = try context.fetch(fetchRequest).first {
labelName.text = user.username
}
} catch {
print("Could not fetch \(error) ")
}
}
It creates the records and assigns the proper indexes. Then entering a number in the text field should work.
But – once again – on each launch of the app the 3 records are inserted again with the same names and indexes. Be aware of that!

Fetch specific attributes from coredata swift

I am developing core data in my application.
I want to fetch name attribute from the core data.
class ViewController: UIViewController {
#IBOutlet weak var saveDataBtn:UIButton!
#IBOutlet weak var dataTxtField:UITextField!
#IBOutlet weak var dataLbl:UILabel!
var tasks: [Task] = []
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
#IBAction func saveDataBtnPressed(_sender : UIButton){
print("Save Data.")
let task = Task(context: context)
task.name = dataTxtField.text
(UIApplication.shared.delegate as! AppDelegate).saveContext()
getData()
}
func getData(){
do{
tasks = try context.fetch(Task.fetchRequest())
}catch{
print("Fetching Failed")
}
}
How can i get it?
Thanks,
In Swift 4, you can access the property directly.
do {
let tasks = try context.fetch(request)
for task in tasks {
print(task.name)
}
} catch let error {
print(error.localizedDescription)
}
UPDATED - How to delete and update an instance of an Entity.
Here are some ideas to organize the code to deal with the updating and deleting.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
extension Task {
// to get an instance with specific name
class func instance(with name: String) -> Task? {
let request = Task.fetchRequest()
// create an NSPredicate to get the instance you want to make change
let predicate = NSPredicate(format: "name = %#", name)
request.predicate = predicate
do {
let tasks = try context.fetch(request)
return tasks.first
} catch let error {
print(error.localizedDescription)
return nil
}
}
// to update an instance with specific name
func updateName(with name: String) {
self.name = name
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
// to delete an instance
func delete() {
context.delete(self)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
}
func howItWorks() {
guard let task = Task.instance(with: "a task's name") else { return }
task.updateName(with: "the new name")
task.delete()
}
In Swift 4.1 and 5. We will use NSPredicate to specify our required condition. NSFetchRequest has a property predicate will set our predicate here as follow.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
let predicate = NSPredicate(format: "username = %#", argumentArray: ["John"]) // Specify your condition here
// Or for integer value
// let predicate = NSPredicate(format: "age > %d", argumentArray: [10])
fetch.predicate = predicate
do {
let result = try context.fetch(fetch)
for data in result as! [NSManagedObject] {
print(data.value(forKey: "username") as! String)
print(data.value(forKey: "password") as! String)
print(data.value(forKey: "age") as! String)
}
} catch {
print("Failed")
}