How do I append an executeFetchRequest result into a array struct - ios

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)
}

Related

fetching core data displaying number of items in array not strings

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] = []

How to check the entity attribute name match, and rewrite(update) data for another attributes?

I'm using Core Data entity with attributes, here is generated subclass code:
extension City {
#nonobjc public class func fetchRequest() -> NSFetchRequest<City> {
return NSFetchRequest<City>(entityName: "City")
}
#NSManaged public var name: String?
#NSManaged public var description: String?
#NSManaged public var temp: Double
#NSManaged public var temp_max: Double
#NSManaged public var temp_min: Double
}
I'm parsing JSON data and handle it through Weather model, and save the data into the database using this code (it's work well):
func saveWeatherData() {
let ad = UIApplication.shared.delegate as! AppDelegate
let context = ad.persistentContainer.viewContext
let city = City(context: context)
city.name = Weather.locationName!
city.description = Weather.details!
city.temp = Weather.temp
city.temp_min = Weather.tempMin
city.temp_max = Weather.tempMax
ad.saveContext()
}
The question is... how can I check the coincidence of city names (name attribute)? and if such a city already exists in the database, instead of creating a new record, overwrite (update) the values of current attributes (description, temp, temp_max, temp_min)?
Thanks.
You simply need to try and fetch an existing object. If the fetch succeeds, update its properties. If a match isn't found then create a new object. Something like:
func saveWeatherData() {
let ad = UIApplication.shared.delegate as! AppDelegate
let context = ad.persistentContainer.viewContext
let fetchRequest:NSFetchRequest<City> = City.fetchRequest()
fetchRequest.predicate = NSPredicate(format:"name = %#",Weather.locationName)
fetchRequest.fetchLimit = 1
do {
let result = try context.fetch(fetchRequest)
let city = result.first ?? City(context: context)
city.name = Weather.locationName!
city.description = Weather.details!
city.temp = Weather.temp
city.temp_min = Weather.tempMin
city.temp_max = Weather.tempMax
ad.saveContext()
}
catch {
print("Error fetching city: \(error.localizedDescription)"
}
}

How to cast Core Data queryset to mutable Array in Swift?

There is a code containing description of Dictionary struct and receiving corresponding entries from Core Data
What string(s) should I insert before last bracket to cast NSArray to array of dictionaries?
struct Dictionary {
var name: String
var enableDirect: Bool
var enableReverse: Bool
init(name: String, enableDirect: Bool, enableReverse: Bool) {
self.name = name
self.enableDirect = enableDirect
self.enableReverse = enableReverse
}
}
func loadDictionariesFromStore() -> [Dictionary] {
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Dictionaries")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
}
If you are sure that the NSArray is of type [Dictionary] you can make a forced downcast of results and return it:
return results as! [Dictionary]
// or directly return it
return context.executeFetchRequest(request, error: nil)! as! [Dictionary]

One to many relationship CoreData Swift

Core Data works great for the most part. When I click on name first VC (Items) and performSeque to the second VC (Costs), I can see the costsName and other data. But when I add second name in first VC I can see the same data as in first name.
I'm trying to make a one to many relationship.
I have 2 data models:
import Foundation
import CoreData
#objc(Items)
class Items: NSManagedObject {
#NSManaged var count: NSNumber
#NSManaged var name: String
#NSManaged var cost: NSSet
}
import Foundation
import CoreData
#objc(Costs)
class Costs: NSManagedObject {
#NSManaged var costsDate: NSDate
#NSManaged var costsName: String
#NSManaged var costsValue: NSNumber
#NSManaged var account: Items
}
Here is addAccount's (name of the first VC) save action:
#IBAction func saveButtonPressed(sender: UIBarButtonItem) {
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Items", inManagedObjectContext: managedObjectContext!)
let account = Items(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
account.name = cellOneNameTextField.text
if cellTwoCountTextField.text.isEmpty {
} else {
account.count = (cellTwoCountTextField.text).toInt()!
}
// Saving data
appDelegate.saveContext()
var request = NSFetchRequest(entityName: "Items")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
self.navigationController?.popViewControllerAnimated(true)
}
Here is addCost's save action:
#IBAction func saveButtonTapped(sender: UIBarButtonItem) {
// CoreData Access
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var managedObjectContext = appDelegate.managedObjectContext
let entityDescription = NSEntityDescription.entityForName("Costs", inManagedObjectContext: managedObjectContext!)
let cost = Costs(entity: entityDescription!, insertIntoManagedObjectContext: managedObjectContext!)
cost.costsName = cellThreeNoteTextField.text
cost.costsValue = (cellOnePriceTextField.text).toInt()!
cost.costsDate = datePicker.date
// Saving data
appDelegate.saveContext()
var request = NSFetchRequest(entityName: "Costs")
var error:NSError? = nil
var results:NSArray = managedObjectContext!.executeFetchRequest(request, error: &error)!
for res in results {
println(res)
}
delegate?.refreshTable()
self.navigationController?.popViewControllerAnimated(true)
}
I don't know if you do it somewhere, but your Items should attach a Count object to itself using your cost variable from your Items. Something like :
let account = Items(...)
let cost = Cost(...)
account.cost.addObject(cost)//and changing your var cost:NSSet into var cost:NSMutableSet
//then save Items
(I haven't tried the addObject but you understand the principle)

Return Results from CoreData directly into Class

I'm new to Swift and iOS development. This is probably a simple misconception on my part.
I'm using core data. I have four attributes in my entity:
"title" type String
"longitude", "latitude" type Decimal
"timestamp" type Date
In the code below I'm getting the error "'[Locations]' is not convertible to '()'".
import UIKit
import CoreData
#objc(Locations)
class Locations: NSManagedObject {
#NSManaged var title:String
#NSManaged var longitude:Double
#NSManaged var latitude:Double
#NSManaged var timestamp:NSDate
class func getAllLocations(){
let appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Locations")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
return results as [Locations]
}
}
The compiler complains because you did not specify a return type for your function,
it should be
class func getAllLocations() -> [Locations] { ... }
There are also some unnecessary type annotations, and all the objects can be
declared as constants:
class func getAllLocations() -> [Locations] {
let appDel = (UIApplication.sharedApplication().delegate as AppDelegate)
let context = appDel.managedObjectContext!
let request = NSFetchRequest(entityName: "Locations")
request.returnsObjectsAsFaults = false
let results = context.executeFetchRequest(request, error: nil)!
return results as [Locations]
}
Note also that
let results = context.executeFetchRequest(request, error: nil)!
will throw a runtime exception if the executing the fetch request failed.
You should use an optional binding and some error handling or fallback,
for example
if let results = context.executeFetchRequest(request, error: nil) as? [Locations] {
return results
} else {
// Failed, return empty list. (Alternatively, report error.)
return []
}

Resources