Issue: Saving Json data to Core Data - swift

I am trying to learn how to read data from a blog and save it to core data but the save is not working as intended. There are 4 blog entries and I expect to have 4 different entries in core data. Please see the code below and let me know where i went wrong:
let task = session.dataTaskWithURL(url!, completionHandler:{(data , response, error) -> Void in
if (error != nil){
println(error)
}else{
var jsonResult:NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
var managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext!
let newBlog = NSEntityDescription.insertNewObjectForEntityForName("BlogDetails",inManagedObjectContext:managedObjectContext) as NSManagedObject
var dateFormater = NSDateFormatter()
dateFormater.dateFormat = "yyyy-MM-dd HH:mm:ss" //"yyyy-MM-dd"
var readRequest = NSFetchRequest(entityName: "BlogDetails")
for var i = 0; i < ((jsonResult["items"] as? NSArray)?.count)!; i++ {
var item = jsonResult["items"]![i] as NSDictionary
var blogAuthorDirectory = item["author"]! as NSDictionary
var blogAuthor = blogAuthorDirectory["displayName"] as NSString
var blogAuthorImageDirectory = blogAuthorDirectory["image"] as NSDictionary
// concatenate String
var blogAuthorImage = blogAuthorImageDirectory["url"] as NSString
var blogAuthorImageUrl = ("https:" + blogAuthorImage)
var title = item["title"] as String
// convert date from String
var publishedDate:NSDate = dateFormater.dateFromString(stringTmp as NSString)!
// read content
var content = item["content"] as? NSString
// Write it to core data
newBlog.setValue(blogAuthorImageUrl, forKey: "image")
newBlog.setValue(blogAuthor, forKey: "author")
newBlog.setValue(title, forKey: "title")
newBlog.setValue(publishedDate, forKey: "publisheddate")
managedObjectContext.save(nil)
var results = managedObjectContext.executeFetchRequest(readRequest, error: nil)
println(results)
}
}
})
task.resume()
following are the entries in result in the last iteration:
1. It only has 3 dictionary counts out of which values in first 2 count has all items as nil. how is that being generated?
2. With every iteration, it overwrites value in last count and doesn't append it.
Thanks for your help.

If you want to append objects to your CoreData, you need to do insertIntoManagedObjectContext before you call the managedContext.save(nil) method.
However, your
let newBlog = NSEntityDescription.insertNewObjectForEntityForName("BlogDetails",inManagedObjectContext:managedObjectContext) as NSManagedObject
is declared outside of your for loop, so probably no new blog created after each iteration.

Related

swift core data executeFetchRequest always crash with propertiesToGroupBy

i am having a problem with executeFetchRequest when i use propertiesToGroupBy. I need to fetch dates(saved as string) but similar dates should be avoided, so that i get unique date array. below is the code i used
var arrDates: NSArray = NSArray()
let fetchRequestDates = NSFetchRequest(entityName: "Schedule")
fetchRequestDates.propertiesToGroupBy = ["date"]
fetchRequestDates.propertiesToFetch = ["date"]
fetchRequestDates.resultType = .DictionaryResultType
do {
let result = try managedContext.executeFetchRequest(fetchRequestDates)
arrDates = result as NSArray
} catch {
NSLog("Failed to fetch dates: \(error)")
}
the execution doesn't go further
let result = try managedContext.executeFetchRequest(fetchRequestDates)
and causing SIGBART. If I comment
fetchRequestDates.propertiesToGroupBy = ["date"]
it works but will fetch duplicate dates too. what is the work around?

iOS Core Data: Convert result of fetch request to an array

I'm trying to put the results of a fetch request into an array. My code:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "CLIENTS")
var mobClients = [NSManagedObject]()
var arrayAllPhoneNumbers = [String]()
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
mobClients = results as! [NSManagedObject]
for clientPhoneNumber in mobClients {
let myClientPhoneNumber = clientPhoneNumber.valueForKey("clientsMobilePhoneNumber") as! String
print(myClientPhoneNumber)
//The numbers print out just fine, one below the other
//
//Now the results need to go into the array I've declared above ---> arrayAllPhoneNumbers
messageVC.recipients = arrayAllPhoneNumbers // Optionally add some tel numbers
}
} catch
let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
As illustrated, all the phone numbers needs to be captured in an array. How do I accomplish that?
Instead of your for-loop and the code inside it, use this:
arrayAllPhoneNumbers = mobClients.map({ clientPhoneNumber in
clientPhoneNumber.valueForKey("clientsMobilePhoneNumber") as! String
})
messageVC.recipients = arrayAllPhoneNumbers
let request = NSFetchRequest(entityName: "CLIENTS")
let results = (try? managedContext.executeFetchRequest(request)) as? [NSManagedObject] ?? []
let numbers = results.flatMap { $0.valueForKey("clientsMobilePhoneNumber" as? String }
numbers is now an array of your phone numbers.
But like thefredelement said, it's better to subclass it so you can just cast it to that subclass and access the phone numbers directly.
Swift 5 : flatMap is deprecated, use compactMap
let request = NSFetchRequest(entityName: "CLIENTS")
let results = (try? managedContext.executeFetchRequest(request)) as? [NSManagedObject] ?? []
let numbers = compactMap { $0.valueForKey("clientsMobilePhoneNumber" as? String }

Swift get specific NSManagedObject from entity (core data)

I have an entity in my "ProjName.xcdatamodel" with the name "Questions". In this entity I have 5 attributes ("icehockey","volleyball","soccer",...), each with type transformable. Each row (attribute) will be filled with a NSMutableArray.
What I want to do is to get the value of a specific attribute in this entity. This is my code:
func readQuestionsFromCore(sport:NSString) -> NSMutableArray {
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Questions")
request.returnsObjectsAsFaults = false
var results: NSArray = context.executeFetchRequest(request, error: nil)!
var qArr:NSMutableArray!
if results.count > 0 {
var res = results[0] as NSManagedObject
qArr = res.valueForKey("\(sport)") as NSMutableArray
return qArr
} else {
qArr = []
return qArr
}
}
This will ofcourse not work since I take out the first index of the results from the database (results[0] as NSManagedObject) and thus it will crash if that element is not the same as the valueForKey I'm looking for.
How do I get the one result row that I'm looking for? I.e. "soccer", or at least can I somehow loop through the results and compare the keys of each result row so it doesn't crash when I try with the wrong key? Like something like this:
for (res) in results as NSManagedObject {
if(res.key == "soccer") {
qArr = res.valueForKey("soccer") as NSMutableArray
return qArr
}
}
I hope I'm clear in my explanation!
the valueForKey method returns an optional, you can use if let as below
if let questionsArr = res.valueForKey("\(sport)") as? NSMutableArray {
return questionsArr
} else {
return []
}
This works in Xcode 6.3.2, but looks like you are using older one. If so update to latest one.
I'm not sure I clearly understand what you are trying to achieve. But using next function(that using KVC) you can get a list of class properties and than check if the one you need is there:
func getPropertyList(#classToInspect: AnyObject.Type) -> [String]
{
var count : UInt32 = 0
let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count)
var propertyNames : [String] = []
let intCount = Int(count)
for var i = 0; i < intCount; i++ {
let property : objc_property_t = properties[i]
let propertyName = NSString(UTF8String: property_getName(property))!
propertyNames.append(propertyName as String)
}
free(properties)
println(propertyNames)
return propertyNames
}

Swift: Unable to get array values from singleton class

Hi I retrived value from JSON and stored in NSMutableArray. I have tried this like Singleton. I have used empty swift file for this. Datas successfully retrieved and stored in NSMutableArray which is already declared in mainViewController. Then, if I use that NSMutableArray value in mainViewController, it shows empty array.
My coding is below. Kindly guide me.
Empty Swift File
public class json_file{
var prod_Obj = product_mainVC()
class var shared: json_file
{
struct Static
{
static let instance: json_file = json_file()
}
return Static.instance
}
func dataFromJSON()
{
let url = NSURL(string: "http://........--...4900a20659")!
var data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)!
var dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
let dataArray = dict["data"] as [[String:AnyObject]] // The array of dictionaries
for object in dataArray {
let category_name = object["category_name"] as String
prod_Obj.ct_name_arr.addObject(category_name)
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_name = child["sub_category_name"] as String
prod_Obj.sub_ct_name_arr.addObject(sub_category_name)
}
}
println(prod_Obj.ct_name_arr) //Here value is Getting
println(prod_Obj.sub_ct_name_arr) //Here value is Getting
}
}
viewDidLoad
{
json_file.shared.dataFromJSON()
println(ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
println(sub_ct_name_arr) //Prints Empty Array [Intially Declared as NSMutableArray]
}
I was trying understand the problem, but I can't see the product_mainVC. Because this I remake your class with little modifications.
class JsonFile
{
private(set) var categoryNames:[String];
private(set) var subCategoryNames:[String];
class let shared:JsonFile = JsonFile();
private init()
{
self.categoryNames = [];
self.subCategoryNames = [];
}
func dataFromJson()
{
let url = NSURL(string: "http://........--...4900a20659")!
if let data : NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMapped, error: nil)
{
if let dict: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary
{
if let dataArray = dict["data"] as? [[String:AnyObject]] // The array of dictionaries
{
for object in dataArray {
let category_id = object["category_id"] as Int
let category_name = object["category_name"] as String
categoryNames.append(category_name);
let category_child = object["category_child"] as [[String:AnyObject]]
for child in category_child {
let sub_category_id = child["sub_category_id"] as Int
let sub_category_name = child["sub_category_name"] as String
subCategoryNames.append(sub_category_name);
}
}
}
}
}
println(categoryNames);
println(subCategoryNames);
}
}
I did
Modify your way to do Singleton to a safe and more simple mode, create the arrays categoryNames and subCategoryNames internal in class because this is better to manipulate, and protect your fetch data to safe from possibles crash.
Implementation
JsonFile.shared.dataFromJson();
println("count categoryNames");
println(JsonFile.shared.categoryNames.count);
println("count subCategoryNames");
println(JsonFile.shared.subCategoryNames.count);
You need think about
This code is sync, and because this if you have a big data or request slow, the main thread from your application will freeze waiting return and it is bad for your user. Think if is necessary be sync.
let category_id = object["category_id"] as Int is never used. Why do you stay with this in code?

Core Data EXC_BREAKPOINT

Here is the code that I have used throughout my project without any issues:
var results: NSArray = context.executeFetchRequest(request, error: &error)!
Yet it's crashing! Any ideas why??
More code:
//now get old current and revoke that
var context:NSManagedObjectContext = self.appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "DownloadedCharacters")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "isCurrent = %#", true)
var results: NSArray = context.executeFetchRequest(request, error: &error)!
//error check
if results.count == 1 {
//good
let object:NSManagedObject = results[0] as NSManagedObject
object.setValue(false, forKey: "isCurrent")
println("Revoked old current Object, 1")
//update currents
//find the new object in storage based off saved name
let lookupName = cell.cellData?.valueForKey("saveName") as String
var request2 = NSFetchRequest(entityName: "DownloadedCharacters")
request2.returnsObjectsAsFaults = false
request2.predicate = NSPredicate(format: "saveName = %#", lookupName)
var results2:NSArray = context.executeFetchRequest(request2, error: &self.error)!
if results2.count == 1 {
let object = results2.firstObject as NSManagedObject
object.setValue(true, forKey: "isCurrent")
println("Updated new current")
} else {
println("Fatal error in retreving object for Core Data. Count = \(results.count).")
}
//now update the section of the table
tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.Automatic)
}
Very frustrating. Also, AFTER the problematic line, println("Revoked old current Object, 1") IS being called and IS printing to console.......... any help would be much appreciated