Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store Integers in Core Data using Swift and XCode

While Strings appears to be fine I'm having some trouble storing Integers into Core Data. Following tutorials and reading available information out there doesn't seem to be helping me who has no Objective-C background. (Swift seemed like a straight forward language like the languages I'm fluent with PHP/OOPHP/JavaScript/VBScript/... thus I started playing with it and so far have been able to do everything I wanted, almost)

What I want to do now is, to receive the JSON data and store it into Core Data

Here's my Core Data

Entity name: Category

Its Attributes:

id Int16
title String
description String

My Swift model? file: Category.swift

import CoreData

class Category: NSManagedObject {
    @NSManaged var id: Int //should I declare this as Int16?
    @NSManaged var title: String
    @NSManaged var description: String
}

I'm using SwiftyJASON extension? and NSURLSession protocol? to get the data and to parse it as follow:

import UIKit
import CoreData

class ViewController: UIViewController {

    let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext

    override func viewDidLoad() {
        super.viewDidLoad()
        fetchData()
    }
        func fetchData() {
            var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
            var session = NSURLSession.sharedSession()
            session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
                // parse data into json
                let json = JSONValue(data)
                let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: self.managedObjectContext)
                let category = Category(entity: entityDescription, insertIntoManagedObjectContext: self.managedObjectContext)
                for item in json.array! {
                    category.id = item["id"].string!.toInt()! //goes KABOOM!
                    category.title = item["title"].string!
                    category.description = item["description"].string!
                    managedObjectContext?.save(nil)
                }
                dispatch_async(dispatch_get_main_queue()) {
                    // do something
                }
            }).resume()
        }
}

Let's assume the JASON data is:

[{"id":"1","title":"cat1","description":"blabala one"},{"id":"2","title":"cat2","description":"blabala two"}]

At line where it says category.id = item["id"].string!.toInt()! xCode goes KABOOM, what am I doing wrong here?

Notes/More questions:

  • I tried changing id type within Core Data to Int32 and then declaring it as just Int in the model (and not Int16 or Int32) which reduced some errors but xCode still crashes

  • Probably the way I'm looping stuff is not the best way to do this, what's the better way of storing array of data into core data at once?

  • Most of the tutorials I've seen there's no id's for Entities(tables), am I missing something here?

References:

  • SiftyJSON: https://github.com/lingoer/SwiftyJSON
  • Core Data tutorial: http://rshankar.com/coredata-tutoiral-in-swift-using-nsfetchedresultcontroller/

EDIT > Working code:

Category.swift model file which can be auto generated using File>New>File>iOS>Core Data>NSManagedObject subclass [swift, no need for bridging header but you need to manually add @objc line as below]

import CoreData

@objc(Category) //Wouldn't work without this
class Category: NSManagedObject {
    @NSManaged var id: NSNumber //has to be NSNumber
    @NSManaged var title: String
    @NSManaged var mydescription: String //"description" is reserved so is "class"
}

ViewController.swift

import UIKit
import CoreData

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        fetchData()
    }
    func fetchData() {
        var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
        var session = NSURLSession.sharedSession()
        session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
            let json = JSONValue(data)
            let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext //this line had to be moved here
            let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: managedObjectContext)
            for item in json.array! {
                let category = Category(entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext) //this line has to be in inside for loop
                category.id = item["id"].string!.toInt()!
                category.title = item["title"].string!
                category.mydescription = item["description"].string!
                managedObjectContext?.save(nil)
            }
            dispatch_async(dispatch_get_main_queue()) {
                // do something
            }
        }).resume()
    }
}

Sample fetching data code:

func requestData() {
    let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let context:NSManagedObjectContext = appDel.managedObjectContext!
    var request = NSFetchRequest(entityName: "Category")
    request.returnsObjectsAsFaults = false
    var results:NSArray = context.executeFetchRequest(request, error: nil)
    //println(results)
    for category in results {
        var cat = category as Category
        println("\(cat.id),\(cat.title),\(cat.mydescription)")
    }
}

P.S. Make sure to Clean your project and delete the app from simulator after changing Model

like image 805
Nick Germi Avatar asked Aug 15 '14 04:08

Nick Germi


2 Answers

Scalar types (integers, floats, booleans) in core data are broken in the current Swift beta (5). Use NSNumber for the properties, and file a radar.

object.intProperty = NSNumber(int:Int(item["id"] as String))

(Typed on the phone, so sorry if that's wrong, and I know it's disgusting code - hence, file a radar!)

Or, in your specific case, looking at the JSON, use String. Those IDs are coming in as strings anyway.

like image 146
jrturton Avatar answered Oct 16 '22 15:10

jrturton


Updated for Swift 2

If your JSON data is really of type [[String:String]], you can use the following code in order to set category.id:

if let unwrappedString = item["id"], unwrappedInt = Int(unwrappedString) {
    category.id = unwrappedInt
}
like image 32
Imanou Petit Avatar answered Oct 16 '22 13:10

Imanou Petit