Getting data out of an NSManagedObject - ios

I have a fetch to core data that returns a NSManagedObject like so
let results = try context.fetch(data);
let resultset = results as! [NSManagedObject];
I have a string array created like so:
var db: [String] = [];
My core data has a column called blogs.
How do I get that entire column into my db variable?
Blogs column is a string.
New to core data too.

Use the map function
let results = try context.fetch(data) as! [NSManagedObject]
db = results.map { $0.value(forKey: "blogs") as! String }
or – preferable – if your are using NSManagedObject subclass and generic entity
let results = try context.fetch(data)
db = results.map { $0.blogs }
And remove the semicolons in your code by the way...

Related

How to convert string to array in Swift 3

I am inserting an Array into my database as a String and after fetching it I want it to convert it again to Array. So that I can fetch my values again and I can do next operation.
Here below is my array inserting into database(TestQuestion) as a String:
let testQuestionModel : TestQuestion = NSEntityDescription.insertNewObject(forEntityName: "TestQuestion", into: AppDelegate.getContext()) as! TestQuestion
testQuestionModel.optionsArray = "\(question["options"] as! NSArray)"
Example: String Array I am getting from Database
(\n \"Rahul Abhyankar\",\n \"Pinkesh Shah\",\n \"Ramanan
Ganesan\",\n \"Dr. Marya Wani\",\n \"\",\n \"\"\n)".
Here is 4 options you can see this is my string after fetching from Database.
1) Rahul Abhyankar.
2) Pinkesh Shah.
3) Ramanan Ganesan.
4) Dr. Marya Wani.
Now how can I convert it into array?
I tried some methods.
let arr = NSArray(object: quetion.optionsArray!).
But I am getting only one object. How can I get my array values same as previous from this string array?
I don't know about the actual type of the "option" in your code, so I set up a fake Elem struct to represent it. The remaining logic is independent of the type as long as you provide a conversion logic to and from String.
struct Elem {
// let's say this is your element type in your array
let foo: Int;
}
extension Elem: CustomStringConvertible {
var description: String {
// provide a logic to convert your element to string
return "\(foo)";
}
}
let arrayToSave = [
Elem(foo: 1),
Elem(foo: 2),
Elem(foo: 3)
]
extension Elem {
init(string: String) {
// provide a function to construct your element type from a string
self.init(foo: Int(string)!)
}
}
let stringToSave = arrayToSave.map { $0.description }.joined(separator: "|")
// save this string
// at some point retrieve it from database, which hopefully same as the saved one
let retrivedString = stringToSave;
let retrivedArray = retrivedString.split(separator: "|").map { Elem(string: String($0)) }
print(retrivedArray) // [1, 2, 3]
Here below is my array inserting into database (TestQuestion) as a
String :
let testQuestionModel : TestQuestion = NSEntityDescription.insertNewObject(forEntityName: "TestQuestion", into: AppDelegate.getContext()) as! TestQuestion
testQuestionModel.optionsArray = "\(question["options"] as! NSArray)"
No, and No.
You are using -description method of an array to save it. Clearly no.
What's wrong? Apple can't affirm that in next OS release, it won't add an extra character. In some more complex cases, it's added <NSArray <0x address> or stuff similar like that.
Suggestion 1:
Modify your entity to have an ARRAY (or usually a Set) of String.
Learn about Core-Data relationship (but that's clearly a DataBase basic knownledge). A relationship one to many should be the thing to do.You could even keep in memory what were the choices, by adding for creating the entity Options, with a String property name (name of the option), another one boolean isChecked, etc.
Suggestion 2:
If you have a limited number of options (like says one to 5), add 5 options string to your entity, and iterate to set them
testQuestionModel.option1 = question["option"][0]
testQuestionModel.option2 = question["option"][1] (if it's of course not out of range for the array)
...
Suggestion 3:
Not really recommended (in my opinion it's missing the whole advantage of the database, especially fetch and predicates, on previous sample you could fetched easily which options were checked), but if you still want to save them as a String, save them as JSON (ie. stringified).
In pseudo code (I'm not sure about the exact syntax, there are no fail safe like try/catch, optional/wrapping):
let options = questions["options"] as [String]
let jsonData = JSONSerialization.data(withJSONObject: (question["options"], options:[])
let jsonString = String.init(data:jsonData encoding:.utf8)
To retrieve them:
let options = JSONSerialization.jsonObject(with data: myJSONString.data(encoding:.utf8), options:[]) as [String]
done using Library SwiftyJSON.
if let dataFromString = yourString?.data(using: String.Encoding.utf8, allowLossyConversion: false) {
do{
let json = try JSON(data: dataFromString)
print(json)
let arrayValue = json.rawValue as! NSArray
print(arrayValue)
} catch{
print(error.localizedDescription)
}
}
Source: https://github.com/SwiftyJSON/SwiftyJSON

Adding up an attribute inside entity for CoreData ios 10

I have a tableView and that tableview is being populated with data from Coredata. The data breaks down like this.
Entity - Person
Entity - Statement
The statement entity has an attribute called amountOwed and it is of decimal type.
The relationships is that a person can have many statements, but each statement belongs to a single person.
Here is the path of the data that I would like to add up. Person > Statement > AmountOwed.
In the tableView function I have a let that represents the Person entity.
let person = fetchedResultsController.object(at: indexPath)
I know its working because I can print out the persons name like so
print(person.name) // Bob
What I want to be able to do is add up all the amountOwed attributes for each Person inside the Statement entity and display them on a cell.
I have been trying to follow an example of calculated fetches but I seem to not quiet understand how to target my Statements Entities which are linked to each Person entity.
let fetchRequest = NSFetchRequest<NSDictionary>(entityName:"statement")
fetchRequest.resultType = .dictionaryResultType
let sumExpressionDesc = NSExpressionDescription()
sumExpressionDesc.name = "sumDeals"
let specialCountExp = NSExpression(forKeyPath: #keyPath(Person.statement[indexPath].amountOwed))
sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments: [specialCountExp])
sumExpressionDesc.expressionResultsType = .interger32AttributeType
fetchRequest.propertiesToFetch = [sumExpressionDesc]
do{
let results = try coreDataStack.managedContext.fetch(fetchRequest)
let resultDict = results.first!
let numDeals = resultDict["sumDeals"]
print(numDeals!)
}
catch let error as NSError{
print("Count not fetched \(error), \(error.userInfo)")
}
Do I need to fetch a Statement entity or should I just use the FetchedREsultsController? If I do use my fetchedResultsController does the keypath to the Statement Entity look like this
person[indexPath].statement.amountOwed
You can do that in one line. If the relationship from Person to Statement is called statements, you get the total of the amounts with
let amountTotal = newPerson.value(forKeyPath: "statements.#sum.amount") as? Int64
Change the downcast at the end from Int64 to whatever is appropriate for your amount attribute-- Double or whatever.
OK on your People+CoreDataClass add:
var totalOwed: Float {
get {
var value: Float = 0
if let statements = self.statements.allObjects() as? [Statement] {
for s in statements {
value = value + s.sum
}
}
return value
}
}
And remove all the code from your fetch that is unnecessary

How to access data index in CoreData using Swift3

I saved datas in entity of CoreData. Also I can access data in CoreData through object.value(forKey:"attribute"). But, I don't know how to access data using index.
follow code is my access way
let context = getContext()
let fetchRequest : NSFetchRequest<Entity> = Entity.fetchRequest()
let result = try? context.fetch(fetchRequest){
for object in result
object.value(forKey:"attribute")...
...
}
}
How to access data in CoreData using index of data?
Your result is type of Array so you can access the object from result like result[0] and so on.
if index < result.count {
let obj = result[index]
}
If you want index from object, you can use index(of:) for that.
if let index = result.index(of: obj) {
print(index)
}

Getting value from json response Swift

[{
"_text" = "turn off the air con";
confidence = "0.609";
entities = {
"on_off" = (
{
value = off;
}
);
};
intent = "aircond_temperature";
}]
I have a json response named "outcomes", and I would like to extract the "off" value from "on_off".
So far what I've done is to get the first element from the response and then cast it to an NSDictionary which works fine, and then using object for key to get the values of each dictionary, and casting them to their respective types.
let firstOutcome:NSDictionary = outcomes.first as! NSDictionary
let intent:String = firstOutcome.objectForKey("intent") as! String
let entities:NSDictionary = firstOutcome.objectForKey("entities") as! NSDictionary
But when it comes to entities I have no idea what type should I cast "on_off" to. Any ideas?
your "on_off" key contain array of dictionaries, so you could try to access it by using this code.
let entities:NSDictionary = firstOutcome.objectForKey("entities") as! NSDictionary
let onOff = entities["on_off"] as! NSArray
let firstValue = onOff.firstObject as! NSDictionary
print(firstValue["value"])
The brackets tell the whole story. { is an object or dictionary, ( is an array. So, entities is a dictionary containing an array of dictionaries, where the inner dictionary has string keys and values.
Try this code:
let entities = entities["on_off"]
for var entity in entities {
print_r(entity["value"])
}

Sort entities based on fetched property

In my application (written in Swift) I use a model for Core Data with two configurations, each of these uses different save path (one is read-only in the application bundle and another is in the Documents folder). I set in one of two configurations an entity "Domanda" with the following attributes:
In the other configuration I set an entity "StatDomanda" with the following attributes:
"StatDomanda" is used for user data, while "Domanda" is used as preloaded source. I know that I can't set up a relationship between the two entities (two configurations), but I would order the "Domanda" entity based on the "corrette" attribute of the "StatDomanda" entity where StatDomanda.numero == Domanda.numero and StatDomanda .argomento == Domanda.argomento.nomeArgomento.
Not all "Domanda" objects have corresponding "StatDomanda" objects.
I set a fetched property (called "statistiche") in the "Domanda" entity with this predicate
$FETCH_SOURCE.numero = numero AND
$FETCH_SOURCE.argomento.nomeArgomento = argomento
but I do not understand how to use it to order the objects.
Thanks for the help!
I found a solution, I don't know if is the best way but it works!
In my core data manager class (ModelManager) I have this function used to fetch all the "Domanda" entities:
func getAllQuestions() -> [Domanda] {
let fetchRequest = NSFetchRequest(entityName: "Domanda")
let fetchResults = managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [Domanda]
return fetchResults!
}
In my ViewController I use this code to obtain the sorted array of "Domanda" entities based on attribute "corrette" of "statistiche" fetched property:
override func viewDidLoad() {
super.viewDidLoad()
var arrayDomande = ModelManager.instance.getAllQuestions()
var sortedArrayDomande = self.sortArray(arrayToSort: arrayDomande)
}
func sortArray(arrayToSort sarray: Array<Domanda>) -> Array<Domanda> {
// 1 - Filter the array to find only questions that have stats
var onlyAnswered = sarray.filter({($0.valueForKey("statistiche") as [Domanda]).count == 1})
// 2 - Sort the array based on fetched property
var sortedArrayDomande = sorted(onlyAnswered, {
let first = ($0.valueForKey("statistiche") as [StatDomanda])[0]
let firstC = first.corrette.integerValue
let second = ($1.valueForKey("statistiche") as [StatDomanda])[0]
let secondC = second.corrette.integerValue
return firstC > secondC
})
return sortedArrayDomande
}
or even in condensed form:
// 2 - Sort the array based on fetched property
var sortedArrayDomande = sorted(onlyAnswered, {($0.valueForKey("statistiche") as [StatDomanda])[0].corrette.integerValue > ($1.valueForKey("statistiche") as [StatDomanda])[0].corrette.integerValue})
Goodbye guys, see you next time!

Resources