Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inserting an NSManagedObject in Swift with a To-One Relationship

I'm having trouble simply inserting an NSManagedObject with a to-one relationship when using Swift on Xcode 6b3.

I put my repro on GitHub but the failing code (in SwiftCoreDataRelationshipReproTests.swift's testSwiftToOne unit test method) boils down to this:

let momURL : NSURL = NSBundle.mainBundle().URLForResource("SwiftCoreDataRelationshipRepro",
    withExtension: "momd")
let mom : NSManagedObjectModel = NSManagedObjectModel(contentsOfURL: momURL)
let psc : NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: mom);
let ps : NSPersistentStore = psc.addPersistentStoreWithType(
    NSInMemoryStoreType,
    configuration: nil,
    URL: nil,
    options: nil,
    error: nil)
let moc : NSManagedObjectContext = NSManagedObjectContext()
moc.persistentStoreCoordinator = psc

// This throws an NSInvalidArgumentException: "An NSManagedObject of class 'NSManagedObject' must have a valid NSEntityDescription."
NSManagedObject(
            entity: NSEntityDescription.entityForName("Pet", inManagedObjectContext: moc),
            insertIntoManagedObjectContext: moc)

That seems like it should work. Nothing tricky.

My very similar Person entity with a to-many relationship can be inserted (and saved) correctly with Swift (as evidenced in the passing testSwiftToMany test) . The more-complicated Objective-C version also succeeds with the same data model (the passing testObjcToOneAndToMany test).

Here's the entire exception:

file:///%3Cunknown%3E: test failure: -[SwiftCoreDataRelationshipReproTests testSwiftToOne()] failed: failed: caught "NSInvalidArgumentException", "An NSManagedObject of class 'NSManagedObject' must have a valid NSEntityDescription."
(
    0   CoreFoundation                      0x00007fff8dd6525c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff84ce5e75 objc_exception_throw + 43
    2   CoreData                            0x00007fff8765dd16 -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] + 550
    3   SwiftCoreDataRelationshipReproTests 0x0000000100394d4a _TTOFCSo15NSManagedObjectcfMS_FT6entityGSQCSo19NSEntityDescription_30insertIntoManagedObjectContextGSQCSo22NSManagedObjectContext__S_ + 42
    4   SwiftCoreDataRelationshipReproTests 0x00000001003946bd _TFCSo15NSManagedObjectCfMS_FT6entityGSQCSo19NSEntityDescription_30insertIntoManagedObjectContextGSQCSo22NSManagedObjectContext__S_ + 93
    5   SwiftCoreDataRelationshipReproTests 0x0000000100393450 _TFC35SwiftCoreDataRelationshipReproTests35SwiftCoreDataRelationshipReproTests14testSwiftToOnefS0_FT_T_ + 816
    6   SwiftCoreDataRelationshipReproTests 0x00000001003934c2 _TToFC35SwiftCoreDataRelationshipReproTests35SwiftCoreDataRelationshipReproTests14testSwiftToOnefS0_FT_T_ + 34
    7   CoreFoundation                      0x00007fff8dc50a5c __invoking___ + 140
    8   CoreFoundation                      0x00007fff8dc508c4 -[NSInvocation invoke] + 308
    9   XCTest                              0x00000001003b023a -[XCTestCase invokeTest] + 253
    10  XCTest                              0x00000001003b03ac -[XCTestCase performTest:] + 142
    11  XCTest                              0x00000001003b8ad0 -[XCTest run] + 257
    12  XCTest                              0x00000001003af68b -[XCTestSuite performTest:] + 379
    13  XCTest                              0x00000001003b8ad0 -[XCTest run] + 257
    14  XCTest                              0x00000001003af68b -[XCTestSuite performTest:] + 379
    15  XCTest                              0x00000001003b8ad0 -[XCTest run] + 257
    16  XCTest                              0x00000001003af68b -[XCTestSuite performTest:] + 379
    17  XCTest                              0x00000001003b8ad0 -[XCTest run] + 257
    18  XCTest                              0x00000001003acc8f __25-[XCTestDriver _runSuite]_block_invoke + 56
    19  XCTest                              0x00000001003b773d -[XCTestObservationCenter _observeTestExecutionForBlock:] + 162
    20  XCTest                              0x00000001003acbc8 -[XCTestDriver _runSuite] + 269
    21  XCTest                              0x00000001003ad34a -[XCTestDriver _checkForTestManager] + 551
    22  XCTest                              0x00000001003bb879 +[XCTestProbe runTests:] + 175
    23  Foundation                          0x00007fff8e0aacb7 __NSFireDelayedPerform + 333
    24  CoreFoundation                      0x00007fff8dccc494 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    25  CoreFoundation                      0x00007fff8dccbfcf __CFRunLoopDoTimer + 1151
    26  CoreFoundation                      0x00007fff8dd3d5aa __CFRunLoopDoTimers + 298
    27  CoreFoundation                      0x00007fff8dc87755 __CFRunLoopRun + 1525
    28  CoreFoundation                      0x00007fff8dc86f25 CFRunLoopRunSpecific + 309
    29  HIToolbox                           0x00007fff8e566a0d RunCurrentEventLoopInMode + 226
    30  HIToolbox                           0x00007fff8e566685 ReceiveNextEventCommon + 173
    31  HIToolbox                           0x00007fff8e5665bc _BlockUntilNextEventMatchingListInModeWithFilter + 65
    32  AppKit                              0x00007fff8538e26e _DPSNextEvent + 1434
    33  AppKit                              0x00007fff8538d8bb -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
    34  AppKit                              0x00007fff853819bc -[NSApplication run] + 553
    35  AppKit                              0x00007fff8536c7a3 NSApplicationMain + 940
    36  SwiftCoreDataRelationshipRepro      0x000000010000ad55 top_level_code + 37
    37  SwiftCoreDataRelationshipRepro      0x000000010000ad8a main + 42
    38  libdyld.dylib                       0x00007fff861115fd start + 1
)
like image 987
rentzsch Avatar asked Jul 11 '14 01:07

rentzsch


People also ask

How do I set up NSManagedObject?

From the Xcode menu bar, choose Editor > Create NSManagedObject Subclass. Select your data model, then the appropriate entity, and choose where to save the files. Xcode places both a class and a properties file into your project.

What is relationship in Core Data?

Inverse relationships enable Core Data to propagate change in both directions when an instance of either the source or destination type changes. Every relationship must have an inverse. When creating relationships in the Graph editor, you add inverse relationships between entities in a single step.


1 Answers

So I couldn't solve the problem, but I think I narrowed it down to a bug in the framework or Swift. Using entityForName is equivalent to getting the entity directly out of the managedObjectModel so I tried to do it that way:

let entities = moc.persistentStoreCoordinator.managedObjectModel.entitiesByName;
let keys = Array(entities.keys)
let petVar : String = keys[1] as String
let isEqual1 = (petVar == "Pet") // true
let isEqual2 = (petVar.hashValue == "Pet".hashValue) // true

let result1 = entities["Pet"] // nil
let result2 = entities[petVar] // non-nil
let result3 = entities.bridgeToObjectiveC().objectForKey("Pet".bridgeToObjectiveC()) // nil
let result4 = entities.bridgeToObjectiveC().objectForKey(petVar.bridgeToObjectiveC()) // non-nil

// Doesn't Pass
XCTAssertNotNil(NSEntityDescription.entityForName("Pet", inManagedObjectContext: moc));

// Passes
XCTAssertNotNil(NSEntityDescription.entityForName(petVar, inManagedObjectContext: moc));

It works with the key pulled out of the dictionary but not a string that is equivalent to the key (even the hash values are the same).

I think that this pretty definitely shows that there is a bug either in the framework or in Swift itself. I am running Xcode (6b3) and 10.9.4

I think it is time for a bug report.

like image 191
drewag Avatar answered Nov 15 '22 09:11

drewag