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
)
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With