Store Integers in Core Data using Swift and XCode

10,252

Solution 1

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.

Solution 2

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
}
Share:
10,252
Nick Germi
Author by

Nick Germi

Updated on June 13, 2022

Comments

  • Nick Germi
    Nick Germi almost 2 years

    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:

    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