I am new and dont understand to any objC, and there is no swift tut.
I am doing app for week planing, i have button, that add me to every day
-name
-codeName
-Task01
.
.
-Task10
but if i want to edit one specific day, with another button, i always delete rest of the days, resp. i create new entity with a lot of nils and only the one day is full of information. here is my ghetto solution but it's not working right, it's working a few times, then it said it has about 512 searchResults.count and start lagging and dont work...
Please help me, how to change value of specific Attributes and dont create new entity
Here is my code for edit tuesday( rest of the week is same as monday, but its long code, so here is only code with monday and tuesday):
func getAndPrintData () {
let fetchRequest: NSFetchRequest<Workout> = Workout.fetchRequest()
do {
let searchResults = try getContext().fetch(fetchRequest)
print ("num of results = \(searchResults.count)")
for works in searchResults as [NSManagedObject] {
if let moc = managedObjectContext {
let workout = Workout(context: moc)
workout.mondayNameCD = works.value(forKey: "mondayNameCD") as! String?
workout.mondayCodeNameCD = works.value(forKey: "mondayCodeNameCD") as! String?
workout.mondayTask01 = works.value(forKey: "mondayTaks01") as! String?
workout.mondayTask02 = works.value(forKey: "mondayTaks02") as! String?
workout.mondayTask03 = works.value(forKey: "mondayTaks03") as! String?
workout.mondayTask04 = works.value(forKey: "mondayTaks04") as! String?
workout.mondayTask05 = works.value(forKey: "mondayTaks05") as! String?
workout.mondayTask06 = works.value(forKey: "mondayTaks06") as! String?
workout.mondayTask07 = works.value(forKey: "mondayTaks07") as! String?
workout.mondayTask08 = works.value(forKey: "mondayTaks08") as! String?
workout.mondayTask09 = works.value(forKey: "mondayTaks09") as! String?
workout.mondayTask10 = works.value(forKey: "mondayTaks10") as! String?
workout.tuesdayNameCD = DayName.text!
workout.tuesdayCodeNameCD = CodeNameTextField.text!
workout.tuesdayFocusCD = IconImageTextField.text!
workout.tuesdayTask01 = Task01TextField.text!
workout.tuesdayTask02 = Task02TextField.text!
workout.tuesdayTask03 = Task03TextField.text!
workout.tuesdayTask04 = Task04TextField.text!
workout.tuesdayTask05 = Task05TextField.text!
workout.tuesdayTask06 = Task06TextField.text!
workout.tuesdayTask07 = Task07TextField.text!
workout.tuesdayTask08 = Task08TextField.text!
workout.tuesdayTask09 = Task09TextField.text!
workout.tuesdayTask10 = Task10TextField.text!
}
}
} catch {
print("Error with request: \(error)")
}
saveToCoreData() {
self.navigationController!.popToRootViewController(animated: true)
}
}
func saveToCoreData(completion: #escaping ()->Void){
managedObjectContext!.perform {
do {
try self.managedObjectContext?.save()
completion()
print("Product saved to CoreData")
} catch let error {
print("Could not save Product to CoreData: \(error.localizedDescription)")
}
}
}
var managedObjectContext: NSManagedObjectContext? {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
Inside your for loop, you already have a managed object works. Just update the values on it instead of creating a new Workout.
Related
My code below fetches Core Data. The problem is that the Core Data fetch should display the names. Example "Ron", "Paul", "Joe". Instead it will just be 3 for the number of items in the array. How can I get the name printed on the label?
class tv: UIViewController {
var itemsName : [NSManagedObject] = []
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let FetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Team")
do {
itemsName = try context.fetch(FetchRequest)
}catch {
print("Ashley Tisdale")
}
geroge.text = String(itemsName.count)
view.backgroundColor = UIColor.brown
}
#IBOutlet var geroge: UILabel!
}
You are actually printing the number of items in the array.
Also you should change the FetchRequest like this:
let FetchRequest = Team.fetchRequest()
Now the itemsName is [Team] type.
Now create an array to store the names from the results like this:
var nameArray:[String] = []
for item in itemsName {
nameArray.append(item.name) // here I assume the Team object has the key name which you want to retrieve
}
Now you can have it printed:
george.text = "\(nameArray)"
Edit
Replace this:
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let FetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Team")
do {
itemsName = try context.fetch(FetchRequest)
}catch {
print("Ashley Tisdale")
}
geroge.text = String(itemsName.count)
With this:
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let FetchRequest:NSFetchRequest<Team> = Team.fetchRequest()
do {
itemsName = try context.fetch(FetchRequest)
}catch {
print("Ashley Tisdale")
}
var nameArray:[String] = []
for item in itemsName {
nameArray.append(item.lorde)
}
geroge.text = "\(nameArray)"
And change data type of itemsName from [NSManagedObjects] to [Team] like this:
var itemsName:[Team] = []
I am trying to retrieve all values excluding null from one attribute from my core data during the start of the viewController. But during the for loop the no always fetches value 0 and doesn't increment ahead. So my results.count is 8, then it displays 0 for 8 times and fetching the same value for the attribute.
func searchMark() -> Int
{
do
{
let mngdCntxt = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "AddedBookmark")
let results = try mngdCntxt.fetch(fetchRequest)
//fetchRequest.returnsObjectsAsFaults = false
for no in 0..<results.count{
if let match = results[no] as? AddedBookmark
{
print(no)
let providerNo = match.value(forKey: "providerNo") as! Int
print("providerNo: \(providerNo)")
return providerNo
}
}
catch{}
return 0
}
The value of providerNo is fetched same through the for loop.
You return too soon, so the loop does not even increment once (and that is also why the loop does not crash when no == results.count):
func searchMark() -> Int {
var output = 0
do {
let mngdCntxt = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "AddedBookmark")
let results = try mngdCntxt.fetch(fetchRequest)
for no in 0...(results.count-1) {
if let match = results[no] as? AddedBookmark {
print(no)
let providerNo = match.value(forKey: "providerNo") as! Int
print("providerNo: \(providerNo)")
output = providerNo
}
}
return output
}
catch{}
return output
}
This function may not be exactly what you expect but it shows you how big the loop should be and when to return
If you are
trying to retrieve all values excluding null from one attribute
that implies that you actually want to return an Int array and your force-unwrapped attribute implies that the attribute is declared as non-optional. According to these two assumptions null is meant to be 0
The logical conclusion is to specify a predicate to return all records whose providerNo != 0, map the items to the providerNo values and return that.
func searchMark() -> [Int]
{
do {
let mngdCntxt = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "AddedBookmark")
fetchRequest.predicate = NSPredicate(format: "providerNo != 0")
let results = try mngdCntxt.fetch(fetchRequest) as! [AddedBookmark]
return results.map{ Int($0.providerNo) }
}
catch {
print(error)
return [Int]()
}
}
First off, let me explain my app and its flow. The app opens, and the user creates a profile (stores all the data through Core Data). After the user clicks on create, it sends them to a Console Screen (which displays parts of the information the user input, such as their name through a segue). Theres a tab that lets them EDIT their profile (name, weight, address, etc). When the user edits their info (to change their name, weight, etc), it should also update the info displayed on the Console Page.
I've gotten the data to save and load. The issue I'm having is when trying to edit the data from the Edit Profile screen... The user changes the text in a field, and clicks save. For some reason, the data is NOT saving...at least that's what I believe it to be the issue. When the "Save" button is pressed, the text fields go back to what the user originally input on the Create Profile screen, regardless of what text is input.
Code following...
Person.swift
// This struct would to get the data from the user
struct PInfo {
var firstName: String?
var lastName: String?
var cityState: String?
var streetAddress: String?
var gender: String?
var weight: NSNumber?
var phoneNumber: String?
var contactName: String?
var contactPhone: String?
}
func save(withPersonInfo p: PInfo, withContext context: NSManagedObjectContext) {
let entityDescription = NSEntityDescription.entity(forEntityName: "Person", in: context)
let managedObject = NSManagedObject(entity: entityDescription!, insertInto: context) as! Person
managedObject.firstName = p.firstName
managedObject.lastName = p.lastName
managedObject.cityState = p.cityState
managedObject.streetAddress = p.streetAddress
managedObject.gender = p.gender
managedObject.weight = p.weight as! Int16
managedObject.phoneNumber = p.phoneNumber
managedObject.contactName = p.contactName
managedObject.contactPhone = p.contactPhone
do {
try context.save()
print("Saved Successful")
}
catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
func fetchSingleUser(withContext context:NSManagedObjectContext) -> PInfo {
let request: NSFetchRequest<Person> = Person.fetchRequest()
let coreData_items = try? context.fetch(request)
guard let items = coreData_items,
let firstItem = items.first
else {
fatalError("Error while querying") }
print("Loaded CoreData Items: \(firstItem)")
return PInfo(firstName: firstItem.firstName!, lastName:firstItem.lastName!, cityState: firstItem.cityState!, streetAddress: firstItem.streetAddress!, gender: firstItem.gender!, weight: firstItem.weight as NSNumber, phoneNumber: firstItem.phoneNumber!, contactName: firstItem.contactName, contactPhone: firstItem.contactPhone)
}
func userDataExists(withContext context: NSManagedObjectContext) -> Bool {
let request: NSFetchRequest<Person> = Person.fetchRequest()
let coreData_items = try? context.fetch(request)
guard let items = coreData_items,
let _ = items.first
else {
return false }
return true
}
EditProfileViewController.swift
#IBAction func saveButton(_ sender: UIButton) {
//Save to CoreData
saveUsersInfo()
alertPopup(title: "Saved!", message: "Your information has been updated!")
updateTextFields()
}
func updateTextFields() {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let userInformation = fetchSingleUser(withContext: managedContext)
//Set UI Text Fields with Users Data
firstNameField.text = userInformation.firstName!
lastNameField.text = userInformation.lastName!
weightInputField.text = String(describing: userInformation.weight!)
genderInputField.text = userInformation.gender!
phoneNumberField.text = userInformation.phoneNumber!
streetAddressField.text = userInformation.streetAddress!
cityStateInputField.text = userInformation.cityState!
contactNameField.text = userInformation.contactName
contactPhoneNumberField.text = userInformation.contactPhone
print("Updated User Info Text Fields")
}
func saveUsersInfo() {
//Save to CoreData
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let userInfo = PInfo(firstName: firstNameField.text!, lastName: lastNameField.text!, cityState: cityStateInputField.text!, streetAddress: streetAddressField.text!, gender: genderInputField.text!, weight: Int16(weightInputField.text!)! as NSNumber, phoneNumber: phoneNumberField.text!, contactName: contactNameField.text!, contactPhone: contactPhoneNumberField.text!)
save(withPersonInfo: userInfo, withContext: managedContext)
print("User Info Saved")
updateTextFields()
}
}
I BELIEVE it's an issue with saving (due to debugging), but I'm not familiar enough with CoreData to know exactly what the issue is.
Any help/info is greatly appreciated!
I suspect your data is being saved. But you are creating a new object each time, rather than updating the values of the existing object. Whenever you call your save method, this line:
let managedObject = NSManagedObject(entity: entityDescription!, insertInto: context) as! Person
creates a new Person object. And when you call the fetchSingleUser method, you fetch ALL the Person objects:
let coreData_items = try? context.fetch(request)
but then use only the first of those items:
let firstItem = items.first
It happens that the first item is the original Person object, with the original values: hence the textFields revert to those original values.
If your app should have only one Person object, change the save method to fetch the existing object, and update the property values of that instance, for example in your save method:
var managedObject : Person
let request: NSFetchRequest<Person> = Person.fetchRequest()
let coreData_items = try? context.fetch(request)
if let items = coreData_items {
if items.count > 0 {
managedObject = items.first
} else {
managedObject = NSManagedObject(entity: entityDescription!, insertInto: context) as! Person
}
managedObject.firstName = p.firstName
... etc
} else {
// coreData_items is nil, so some error handling here
}
I'm trying to use reflection in Swift with Core Data entities, but when I execute the following code, my reflected var has only a reference for a super class, it didn't have a reference for any of it's attributes.
func printProperties() {
let mirror = reflect(self)
for var i = 0; i < mirror.count; i++ {
let (propertyName, childMirror) = mirror[i]
println("property name: \(propertyName)")
println("property value: \(childMirror.value)")
}
}
Does anyone have some idea why this happens?
Update: As suggested by Anderson in his answer I tried another approach and ended up with this code:
func loadFromJson(json: JSON) {
for attributeKey in self.entity.attributesByName.keys {
let attributeDescription = self.entity.propertiesByName[attributeKey]!
as! NSAttributeDescription
let attributeClassName = attributeDescription.attributeValueClassName
let jsonValue = json[(attributeKey as! String)]
var attributeValue: AnyObject? = attributeDescription.defaultValue
if jsonValue.type != .Null && attributeClassName != nil {
if attributeClassName == "NSNumber" {
attributeValue = jsonValue.number!
} else if attributeClassName == "NSString" {
attributeValue = jsonValue.string!
}
}
setValue(attributeValue, forKey: (attributeKey as! String))
}
}
I believe that this code can help you.
I wrote this extension to make a dictionary from a NSmanagedObject and it accesses all attributes and values of the object.
extension NSManagedObject {
func toDict() -> Dictionary<String, AnyObject>! {
let attributes = self.entity.attributesByName.keys
let relationships = self.entity.relationshipsByName.keys
var dict: [String: AnyObject] = [String: AnyObject]()
var dateFormater = NSDateFormatter()
dateFormater.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
for attribute in attributes {
if self.entity.propertiesByName[attribute]!.attributeValueClassName != nil && self.entity.propertiesByName[attribute]!.attributeValueClassName == "NSDate" {
let value: AnyObject? = self.valueForKey(attribute as! String)
if value != nil {
dict[attribute as! String] = dateFormater.stringFromDate(value as! NSDate)
} else {
dict[attribute as! String] = ""
}
} else {
let value: AnyObject? = self.valueForKey(attribute as! String)
dict[attribute as! String] = value
}
}
for attribute in relationships {
let relationship: NSManagedObject = self.valueForKey(attribute as! String) as! NSManagedObject
let value = relationship.valueForKey("key") as! String
dict[attribute as! String] = value
}
return dict
}
}
I hope to have helped you.
I'm an iOS newbie developer. I'm trying to import the results of an executeFetchRequest into a structure I created for viewing later into a table. I"m getting "Array index out of range" in func getTasks(), I'm pretty sure I"m supposed to append it, but not sure quite how.
I'm sure there's a better way of setting this up in general. Right now I'm just trying to get things to work. But other suggestions would be appreciated.
import UIKit
import CoreData
var taskMgr: TaskManager = TaskManager()
struct task {
var name = "Un-Named"
var desc = "Un-Described"
}
class TaskManager: NSObject {
var tasks = task[]()
init() {
super.init()
self.getTasks()
}
func addTask(name: String, desc: String) {
tasks.append(task(name: name, desc: desc))
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
let ent = NSEntityDescription.entityForName("Tasks", inManagedObjectContext: context)
var newTask = Tasks(entity: ent, insertIntoManagedObjectContext: context)
newTask.name = name
newTask.desc = desc
println("Object saved")
context.save(nil)
}
func getTasks() {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
var request = NSFetchRequest(entityName: "Tasks")
request.returnsObjectsAsFaults = false;
var results:NSArray = context.executeFetchRequest(request, error: nil)
if (results.count > 0) {
self.tasks = task[]()
var i = 0
for element in results {
tasks[i].name = element.name // fatal error: Array index out of range
tasks[i].desc = element.desc
i++
}
}
}
}
class Tasks: NSManagedObject {
#NSManaged var name: String
#NSManaged var desc: String
}
You can't use subscripting to add items to an array -- you need to call append() or use the += operator instead. Try this:
self.tasks = task[]()
for element in results {
tasks += task(name: element.name, desc: element.desc)
}