11

In Swift previously, I was able to use a code like this to add new data to my "TestEntity" in my data model.

NSManagedObject was created for my "TestEntity" and I was able to set its attributes with the "dot" syntax

At the end, I would save the context

let entity=NSEntityDescription.insertNewObject(forEntityName: "TestEntity", into: context) as! TestEntity
entity.testAttribute="test value"
context.save()

This code does not work in Swift 3. When I run it, i get the following runtime error:

Could not cast value of type 'NSManagedObject_TestEntity_' (0x175306b0) to 'testCoreData.TestEntity' (0xd6bb8). 2016-06-19 11:07:52.305195 testCoreData[689:264453] Could not cast value of type 'NSManagedObject_TestEntity_' (0x175306b0) to 'testCoreData.TestEntity' (0xd6bb8)

Can anyone shed some light on how this should be done in Swift 3?

The second part of the question is how to access the data again. the following code ends with an error:

fatal error: NSArray element failed to match the Swift Array Element type

let fr:NSFetchRequest<TestEntity>=TestEntity.fetchRequest()
        
do {
   let searchResults=try context.fetch(fr)
   if let results=searchResults {
      for result in results {
         print("testAtt = \(result.testAtt)")
      }
   }
} catch {
            
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
matyasl
  • 295
  • 2
  • 11

4 Answers4

10

If there is a NSManagedObject subclass TestEntity the new syntax is

let entity = TestEntity(context: context)
entity.testAttribute="test value"
vadian
  • 274,689
  • 30
  • 353
  • 361
  • 1
    Saving has to be wrapped into `try-catch` blocks. – Mundi Jun 19 '16 at 20:12
  • @Mundi Yes of course, but it's irrelevant for the question. I deleted the line. – vadian Jun 19 '16 at 20:16
  • I had to create NSEntityDescription for the above code to work. without it, I got another runtime error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class 'testCoreData.TestEntity' must have a valid NSEntityDescription.' `let entityDes=NSEntityDescription.entity(forEntityName: "TestEntity", in: context) let entity=TestEntity(entity: entityDes!, insertInto: context) entity.testAtt="test attribute"` But then it worked. Thank you. – matyasl Jun 21 '16 at 11:33
  • There are fundamental changes in Swift 3 regarding Core Data. For example there is a new class `NSPersistentContainer` to manage the creation of the Core Data stack. Create a new project with Core Data enabled to see the changes. – vadian Jun 21 '16 at 11:38
3
//retrieve the entity
let entity =  NSEntityDescription.entity(forEntityName: "TestEntity", in: context)

let testEntity = NSManagedObject(entity: entity!, insertInto: context)

//set the entity values
testEntity.setValue(testAtt1, forKey: "testAtt1")
testEntity.setValue(testAtt2, forKey: "testAtt2")

//save the object
do {
    try context.save()
    print("saved!")
} catch let error as NSError  {
    print("Could not save \(error), \(error.userInfo)")
} catch {

}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Mohamed Hashem
  • 146
  • 2
  • 2
1

working example:

let fr:NSFetchRequest<TestEntity>=TestEntity.fetchRequest()
do {
    let results=try self.moc!.fetch(fr)
    if results.count==0 {
        print("no resutls. i need to add something")
        let newTestEntity=TestEntity(context: self.moc!)
        newTestEntity.testAtt="testovaci text"
        do {
            try self.moc!.save()
        }catch{
            
        }
    }else{
        print("already some results")
        for result in results {
            print(result.testAtt!)
        }
    }
}catch {
    print(error)
}

Data model inspector TestEntity Class name needs to be set to TestEntity. Previous strange behaviour seemed to be caused by this value to be blank.

pkamb
  • 33,281
  • 23
  • 160
  • 191
matyasl
  • 295
  • 2
  • 11
0

I'm not a Core Data expert, but the API offers 3 distinct ways of creating an NSManagedObject instance. I'm not aware if any of them offer any benefit over the other.

Assuming you have an entity/NSManagedObject subclass called TestEntity then all of the below are the same:


New way (no casting required) +iOS10:

let test = TestEntity(context: context)
test.attribute1 = "a value"

Older ways (casting is not required if you're ok with using setValue. With casting you can use dot notation. +iOS3

let testEntity =  NSEntityDescription.entity(forEntityName: "TestEntity", in: context)

let test1 = NSManagedObject(entity: testEntity!, insertInto: context)
test1.setValue("a value", forKey: "attribute1")

let test2 = NSManagedObject(entity: testEntity!, insertInto: context) as! TestEntity
test2.attribute1 = "a value"

or:

let test1 = NSEntityDescription.insertNewObject(forEntityName: "TestEntity", into: context)
test1.setValue("a value", forKey: "attribute1") 

let test2 = NSEntityDescription.insertNewObject(forEntityName: "TestEntity", into: context) as! TestEntity
test2.attribute1 = "a value"

once you create the NSManagedObject instance and assign its attributes then you just save it in the context.

do {
    try context.save()
    print("saved!")
} catch let error as NSError  {
    print("Could not save \(error), \(error.userInfo)")
} catch {

}
pkamb
  • 33,281
  • 23
  • 160
  • 191
mfaani
  • 33,269
  • 19
  • 164
  • 293