Swift and CoreData / Data Storage

22,894

Solution 1

This is how I implemented core data.

A couple of really important notes:

  • You have to add this to your NSManagedObject class:

    @objc(MyObject)

  • You have to add the entity name to your default configuration class in the .xcdatamodel (picture included)

xcdatamodel

  • You can't simply make an NSManagedObject.

    var myObject : MyObject = MyObject()
    

You have to do this:

let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context: NSManagedObjectContext = appDelegate.managedObjectContext
let entityName: String = "MyObject"
let myEntityDescription = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
var myObject = MyObject(entity: myEntityDescription, insertIntoManagedObjectContext: context)

Here is my NSManagedObject. I included two fetch methods as well as a class method for object construction. You may notice that I am taking advantage of the new enum system so that I can easily access my entity names and entity attributes

import UIKit
import CoreData

enum MyObjectPropertyList { 
    case name
    func description() -> String {
        switch self {
        case .name:
            return "name"
        }
    }
}

@objc(MyObject)
class MyObject: NSManagedObject {

    @NSManaged var name: String

    //
    //// CREATE CLASS OBJECT
    //

    class func createMyObject (propertyName:MyObjectPropertyList, value:String, context: NSManagedObjectContext) -> MyObject? {
        if !value.isEmpty {
            let propertyType = propertyName.description()

            let entityName = "MyObject"
            let request : NSFetchRequest = NSFetchRequest(entityName: entityName)
            request.returnsObjectsAsFaults = false
            request.predicate = NSPredicate(format: "\(propertyType) = %@", value)
            var error: NSError? = nil
            var matches: NSArray = context.executeFetchRequest(request, error: &error)

            if (matches.count > 1) {
                // handle error
                return matches[0] as? MyObject
            } else if matches.count ==  0 {
                let entityDescription = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
                var myObject : MyObject = MyObject(entity: entityDescription, insertIntoManagedObjectContext: context)
                myObject.name = value
                return myObject
            }
            else {
                println(matches[0])
                return matches[0] as? MyObject
            }
        }
        return nil
    }
}

    //
    //// FETCH REQUESTS
    //

    func myGeneralFetchRequest (entity : CoreDataEntities,
                              property : MyObjectPropertyList,
                               context : NSManagedObjectContext) -> AnyObject[]?{

        let entityName = entity.description()
        let propertyName = property.description()

        let request :NSFetchRequest = NSFetchRequest(entityName: entityName)
        request.returnsObjectsAsFaults = false
        let sortDescriptor : NSSortDescriptor = NSSortDescriptor(key: propertyName, ascending: true)
        request.sortDescriptors = [sortDescriptor]
        var error: NSError? = nil
        var matches: NSArray = context.executeFetchRequest(request, error: &error)

        if matches.count > 0 {
            return matches
        }
        else {
            return nil
        }
    }

    func myNameFetchRequest (entity : CoreDataEntities,
                           property : MyObjectPropertyList,
                              value : String,
                            context : NSManagedObjectContext) -> AnyObject[]? {

        let entityName = entity.description()
        let propertyName = property.description()

        let request :NSFetchRequest = NSFetchRequest(entityName: entityName)
        request.returnsObjectsAsFaults = false
        request.predicate = NSPredicate(format: "\(propertyName) = %@", value)
        let sortDescriptor :NSSortDescriptor = NSSortDescriptor(key: propertyName, ascending: true)
        request.sortDescriptors = [sortDescriptor]
        var error: NSError? = nil
        var matches: NSArray = context.executeFetchRequest(request, error: &error)

        if matches.count > 0 {
            return matches
        }
        else {
            return nil
        }
    }

    //
    //// PRINT FETCH REQUEST
    //

    func printFetchedArrayList (myarray:AnyObject[]) {
        if myarray.count > 0 {
            println("Has \(myarray.count) object")
            for myobject : AnyObject in myarray {
                var anObject = myobject as MyObject
                var thename = anObject.name
                println(thename)
            }
        }
        else {
            println("empty fetch")
        }
    }

Here is my view controller

import UIKit
import CoreData

enum CoreDataEntities {
    case MyObject
    func description() -> String {
        switch self {
        case .MyObject:
            return "MyObject"
        }
    }
}

class ViewController: UIViewController {

    //
    //// MOC
    //

    var managedObjectContext : NSManagedObjectContext = NSManagedObjectContext()

    //
    //// Text Field
    //

    @IBOutlet var myTextField : UITextField

    //
    //// BUTTONS
    //

    @IBAction func saveButtonPress(sender : UIButton) {
        makeEntityAction()
    }

    @IBAction func fetchButtonPress(sender : UIButton) {
        fetchObjectAction()
    }

    //
    //// ACTIONS
    //

    func makeEntityAction () {
        println("-- Make action --")

        let value:String = self.myTextField.text
        var myObject : MyObject = MyObject.createMyObject(MyObjectPropertyList.name, value : value, context: self.managedObjectContext)!
        saveContext(self.managedObjectContext)
    }

    func fetchObjectAction () {
        println("-- Fetch action --")

        if let myTotalarray = myGeneralFetchRequest(CoreDataEntities.MyObject, MyObjectPropertyList.name, self.managedObjectContext) {
            printFetchedArrayList(myTotalarray)
        }
        if let mySinglearray: AnyObject[] = myNameFetchRequest(CoreDataEntities.MyObject, MyObjectPropertyList.name, "Bill", self.managedObjectContext) {
            println("(--  --)")
            printFetchedArrayList(mySinglearray)
        }

    }

    //
    //// LOAD & SAVE
    //

    func loadContext () {
        let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        let context: NSManagedObjectContext = appDelegate.managedObjectContext
        self.managedObjectContext = context
    }

    func saveContext (context: NSManagedObjectContext) {
        var error: NSError? = nil
        context.save(&error)
    }

    //
    //// LOAD
    //

    func myLoad () {
        loadContext ()
        println("Loaded Context")
    }

    //
    //// Life Cycle
    //

    override func viewDidLoad() {
        super.viewDidLoad()
        myLoad ()
    }

}

Solution 2

All Objective-C frameworks are swift-ready. Swift-friendly headers are automatically generated (on-demand, it appears), and you can access anything from Swift that you can from ObjC.

Solution 3

I had tested use swift to access coredata, please visit the demo code : https://github.com/iascchen/SwiftCoreDataSimpleDemo .

Solution 4

If you wanna have a play around with Swift and CoreData, I've written a framework thats an Active Record style assistant to CoreData.

SuperRecord Swift Framework

(note: not a shameless plug :) i actually thought this would be useful for the user).

Share:
22,894
DanielAsking
Author by

DanielAsking

Updated on January 08, 2020

Comments

  • DanielAsking
    DanielAsking over 4 years

    I'm just learning Objective-C / Cocoa Touch and Core Data. So, what are the new possibilities to implement data storage in iOS App Projects that are written in pure Swift? I really like the language, but as far as I know all core data methods are written in Objective-C. So will the core data classes/methods converted to Swift-Code automatically or will we have to mix up Objective-C Code for Core data and Swift-Code for everything else?

  • Lucas
    Lucas almost 10 years
    Where can we find the headers? Like the equivalent of the documentation in obj-c.
  • rickster
    rickster almost 10 years
    Look in the Reference Library. All the docs show both Swift and ObjC syntax for using an API. Look at Using Swift with Cocoa and Objective-C for more info on how to mix languages, and see the @NSManaged attribute in particular for working with Core Data.
  • Wizard of Kneup
    Wizard of Kneup almost 10 years
    Do I understand your file correctly? You do not have a working demo?
  • Pirijan
    Pirijan almost 10 years
    It is certainly unclear, but running the demo myself it does seem to work. It looks like @IascCHEN uses autogenerated Obj-C NSManagedObject subclass files rather than a Swift only solution (which I'd prefer)
  • Quaternion
    Quaternion almost 10 years
    Preserved comment left in message by user William: You will need to ensure that the text-field is not nil, in addition to that the object you retrieve actually has a name-field. This can be done in conventional if-sentence ways. An example includes: var value:String="default" if(self.myTextField.text != nil) { value=self.myTextField.text }
  • IascCHEN
    IascCHEN over 9 years
    After Xcode 6 beta 3, you can generate swift NSManagedObject, but you should add @objc in the swift code. please check the member.swift file. U can check the running progress from log.