Getting specific attributes from coredata swift - ios

I have a request for an entity in core data:
override func viewWillAppear(animated: Bool) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Constants")
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
Within the entity Constants there are 4 attributes: moneyPerSecondSave,moneySave,tapMultiplierSaveandtapValueSave.
My question is, is there a way that after I have got the results can I make four variables which each hold each of the values of the attributes.
I have already tried using valueForKey:
moneyConstants.money = results.valueForKey("moneySave")
However when I try this it pulls up an error: `Value of type '[AnyObject]' has no member 'valueForKey'. Any help would be appreciated.

'results' is an array which holds 'Any' type. You can cast it to an array with the type you expect and get the rest of the data like this:
if let constants = results as? [Constants] {
let moneyPerSecond = constants[0].moneyPerSecondSave
print("moneyPerSecond: \(moneyPerSecond)")
}
You can also use valueForKey of course, like this:
if let match = results[0] as? Constants {
let money = match.value(forKey: "moneySave") as! Float
print("money: \(money)")
}

You can use propertiesToFetch & resultType attribute of NSFetchRequest to retrieve only specific property values of Constants.
You can take inspiration from https://stackoverflow.com/a/6267875/3339346

Related

Output of fetched data to a variable as an Int

In this example, print gewicht gives an output of optional({10)} i need the output (10) as
an Int assigned to a variable . So the output has to be let mijnGewicht = 10
How can i do that. Iam new to swift, so excuse me for the question.
let appDelegate = UIApplication.shared.delegate as? AppDelegate
let managedObjectContext = appDelegate!.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Dogs")
fetchRequest.predicate = NSPredicate(format: "name = %#", "Toni")
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.relationshipKeyPathsForPrefetching = ["gewicht"]
do {
let fetchedResults = try managedObjectContext.fetch(fetchRequest)
for i in fetchedResults {
dogs.append(i as! NSManagedObject)
for i in dogs {
let gewicht = i.value(forKeyPath: "gewicht.kg")
print(gewicht)
}
Dealing with unspecified NSManagedObject and value(forKeypath: is outdated.
Take advantage of the generic abilities of Core Data. The benefit is no type cast and no Any.
First declare dogs as
var dogs = [Dogs]()
By the way it's highly recommended to name entities in singular form. Semantically you have an array of Dog instances.
Create the fetch request for the specific NSManagedObject subclass Dogs
As gewicht is a to-many relationship you have to use a loop to get all values
let appDelegate = UIApplication.shared.delegate as? AppDelegate
let managedObjectContext = appDelegate!.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Dogs>(entityName: "Dogs")
fetchRequest.predicate = NSPredicate(format: "name = %#", "Toni")
fetchRequest.returnsObjectsAsFaults = false
do {
let result = try managedObjectContext.fetch(fetchRequest)
dogs.append(contentsOf: result)
for dog in dogs {
for gewicht in dog.gewicht {
let kg = gewicht.kg
print(kg)
}
}
} catch { print(error) }
If the relationship and/or the attribute is declared optional (which is still unclear) you have to unwrap the optional.
And consider that the integer value is Int16, Int32 or Int64 (unfortunately this information is missing, too). There is no Int type in Core Data.
And it's up to you how to distinguish the many values.
Try changing your code like this, it checks if the value you are assigning is not nil and then prints it
for i in dogs {
if let mijnGewicht = i.value(forKeyPath: "gewicht.kg"){
print(mijnGewicht)
}
}
You can try something like this
let gewicht = i.value(forKeyPath: "gewicht.kg")
if let gewichtInt = gewicht as? Int {
print(gewichtInt)
}
for i in dogs {
if let gewicht = i.value(forKeyPath: "gewicht.kg") {
print(gewicht) // this will give you the safe value as Int, if the value is nill it will not come in this if condition
}
let x = i.value(forKeyPath: "gewicht.kg") ?? 0
print (x) //this will give you wrapped safe value of gewicht.kg if exists else it will give you 0
}
here in above example i have shown you two ways to safe cast a value from optional, you can also use guard or guard let on the basis of your requirement

Fetching particular attributes or properties in CoreData

i am using following Code to eliminate attributes while fetching from my CoreDataModel called industry. Still i am able to access those attributes which have not requested using fetchRequest.propertiesToFetch
let fetchRequest = NSFetchRequest(entityName: "Industry")
fetchRequest.propertiesToFetch = ["id","industry_name"]
After this i am using following code:
industryObject.industry_name=tuple.value(forKey: ""ind_subtype"") as? String
"ind_subtype" i have not specified in *.propertiesToFetch* and i am still able to access it
func fetchIndustryNamesWithId()->[IndustryData]{
var industryData=[IndustryData]()
//fetchRequest.predicate = NSPredicate(format: "firstName == %#", firstName)
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Industry")
fetchRequest.propertiesToFetch = ["id","industry_name"]
do {
let tuples = try managedObjectContext.fetch(fetchRequest)
for tuple in tuples{
let industryObject=IndustryData()
industryObject.id=tuple.value(forKey: "id") as? Int
industryObject.industry_name=tuple.value(forKey: "industry_name") as? String
industryObject.ind_subtype=tuple.value(forKey: "ind_subtype") as? String
industryData.append(industryObject)
}
return industryData
} catch {
let fetchError = error as NSError
print(fetchError)
}
return industryData
}
This is how it works. When you set propertiesToFetch CoreData will returns ManagedObject as a partially faulted. It means that some of the properties are populated some are not. When you access property that is not populated, core data will fulfil it for you but it probably will have performance impact because in most cases will require roundtrip to row cache.
For more info google for CoreData Faulting

Obtaining an array of objects from fetch request

I have an object called Projects that I save to core data. I then add multiple projects to core data. I want to retrieve those objects as an array from core data. The following code gets this error:
-[NSAsynchronousFetchResult mutableCopyWithZone:]: unrecognized selector sent to instance
var uploadPhotos : NSMutableArray? = []
var activeProject : String!
override func viewDidLoad() {
super.viewDidLoad()
projectPicker.dataSource = self
projectPicker.delegate = self
isInSegmentPhoto = true
//let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Project")
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = Project.fetchRequest()
let entityDescription = NSEntityDescription.entity(forEntityName: "Project", in: sharedDelegate.managedObjectContext)
fetchRequest.entity = entityDescription
do {
let result = try self.sharedDelegate.managedObjectContext.execute(fetchRequest)
print(result)
projects = result.mutableCopy() as! [Project]
} catch {
let fetchError = error as NSError
print(fetchError)
}
}
When I run the program it prints out the list of projects, but crashes on the first line of the do-catch.
Please, please use Swift native types, NSMutableArray has no type information.
var projects = [Project]()
...
projects = try defaultManagedObjectContext().fetch(fetchRequest) as! [Project]
Since the fetch request is clearly a Project request you can safely unwrap the result.
mutableCopy() causes the error, because NSFetchRequestResult(the umbrella protocol of all possible result types) does not respond to that method.
Figured it out! I was using the wrong method. Replace execute with fetch.
self.sharedDelegate.managedObjectContext.fetch(fetchRequest)

Swift: CoreData call to specific object ID

I'm discovering new concepts as a fresh developer, I have been trying to understand core data, and run into an issue with a tutorial I've been walking through. I am getting an error when I call an item using the Object ID. The error is - Type 'Person.Type' has no subscript members. it may be because I am just not doing it correctly, or some other reason. I'm sure someone can shine some light on the subject
Here is a function I wrote to get a specific item out of the Data Stack,
func getObjectById(id: NSManagedObjectID) -> Person?{
return context.objectWithID(id) as? Person
}
Here is how I am calling the function
func callFirstObject(){
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let personService = PersonService(context: context)
let firstPerson = personService.getObjectById(Person[0].objectID!)
}
and from there I am just calling callFirstObject() inside a button.
Edit: I have a function to call all of my objects
func getAllObjects() -> [Person]{
return getObject(withPredicate: NSPredicate(value: true))
}
and a function to call all of my objects with a predicate
func getObject(withPredicate queryPredicate: NSPredicate) -> [Person]{
let fetchRequest = NSFetchRequest(entityName: Person.entityName)
fetchRequest.predicate = queryPredicate
do {
let response = try context.executeFetchRequest(fetchRequest)
print("\(response)")
return response as! [Person]
} catch let error as NSError {
// In case of failure
print("There was an error - \(error)")
return [Person]()
}
}
I am just trying to call a specific name in the stack.
If more information is needed, I am glad to provide.
Person has no subscript members because Person is the class name. The subscript, [0], should be called on an array of Person objects.
That could look something like this:
func callFirstObject(){
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let personService = PersonService(context: context)
// Person Array
let persons: [Person] = [person1, person2, person3 ]
let firstPerson = personService.getObjectById(persons[0].objectID!)
}
Edit: I'm kind of confused the logic though. If you have the person already, you have to in order to access the objectID, then I don't see why you need to fetch it again. Can we see some more context around these two methods?
Answering your question from the comment below:
If you want to get all of the records for the Person model you can do as follows:
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Person")
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
people = results as! [NSManagedObject]
} catch let error as NSError {
print("Could not fetch \(error)")
}
This will give you all of the Person objects stored in Core Data

Getting both attribute name and value when reading from core data

I need to get both the attribute name and the value for the attribute when I'm reading from my core data, is there any easy way of doing this?
I've been trying to retrieve the first element in my object model as a Dictionary, but that gives me an error saying:
fatal error: NSArray element failed to match the Swift Array Element
type
My code looks like this:
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let fetchReq = NSFetchRequest(entityName: "ActiveIndexes")
fetchReq.resultType = NSFetchRequestResultType.DictionaryResultType
receivedList = context.executeFetchRequest(fetchReq, error: nil) as! [ActiveIndexes]
println(receivedList[0])
Any suggestions would be appreciated.
NSManagedObjects have a rich API for introspection.
let activeIndex = retrievedList[0]
for (key, value) in activeIndex.entity.attributesByName {
println("\(key) : \(activeIndex.valueForKey(key as NSString))")
}

Resources