1

I know this has been asked before here but the answer did not solve my problem, and I wanted to post my full test case.

I setup my Entities as in the screenshot: Entities setup image

I had XCode generate a subclass of NSManagedObject:

import Foundation
import CoreData

class Goal: NSManagedObject {
    @NSManaged var displayDesc: String
    @NSManaged var motivation: String
    @NSManaged var cratedDate: NSDate
    @NSManaged var goalType: NSNumber
}

It also created a header file called LifeList-Bridging-Header.h that is empty.

Finally I setup a test case:

import UIKit
import XCTest
import CoreData

class CastExceptionTest: XCTestCase {
    var _managedObjectContext: NSManagedObjectContext? = nil
    var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil
    var _managedObjectModel: NSManagedObjectModel? = nil

    var applicationDocumentsDirectory: NSURL {
        let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        return urls[urls.count-1] as NSURL
    }

    var managedObjectContext: NSManagedObjectContext {
        if !_managedObjectContext {
            let coordinator = self.persistentStoreCoordinator
            if coordinator != nil {
                _managedObjectContext = NSManagedObjectContext()
                _managedObjectContext!.persistentStoreCoordinator = coordinator
            }
        }
        return _managedObjectContext!
    }

    var managedObjectModel: NSManagedObjectModel {
        if !_managedObjectModel {
            //The data model is just an Entity named Goal with 4 attributes one named displayDesc.
            let modelURL = NSBundle.mainBundle().URLForResource("LifeList", withExtension: "momd")
            _managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
        }
        return _managedObjectModel!
    }

    var persistentStoreCoordinator: NSPersistentStoreCoordinator {
        if !_persistentStoreCoordinator {
            let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CastExceptionTest.sqlite")
            var error: NSError? = nil
            _persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
            if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
                abort()
            }
        }
        return _persistentStoreCoordinator!
    }

    func testCase() {
        //Create and save a new Goal
        let entityDescription = NSEntityDescription.entityForName("Goal", inManagedObjectContext: managedObjectContext)
        let goal = Goal(entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext)
        goal.displayDesc = "Test text"
        var error:NSError?
        managedObjectContext.save(&error)

        //Load the entities
        let fetch = NSFetchRequest(entityName: "Goal")
        let objectArray: [AnyObject]? = managedObjectContext.executeFetchRequest(fetch, error: &error)
        for object in objectArray! {
            let goal = object as Goal
            print(goal.displayDesc)
        }
    }
}

The following is the outcome of running the test:

libswift_stdlib_core.dylib`swift_dynamicCastClassUnconditional:
0x105b147c0:  pushq  %rbp
0x105b147c1:  movq   %rsp, %rbp
0x105b147c4:  pushq  %r14
0x105b147c6:  pushq  %rbx
0x105b147c7:  movq   %rsi, %rbx
0x105b147ca:  movq   %rdi, %r14
0x105b147cd:  testq  %r14, %r14
0x105b147d0:  je     0x105b147fe               ; swift_dynamicCastClassUnconditional + 62
0x105b147d2:  movabsq $-0x7fffffffffffffff, %rax
0x105b147dc:  andq   %r14, %rax
0x105b147df:  jne    0x105b147fe               ; swift_dynamicCastClassUnconditional + 62
0x105b147e1:  movq   %r14, %rdi
0x105b147e4:  callq  0x105b29764               ; symbol stub for: object_getClass
0x105b147e9:  nopl   (%rax)
0x105b147f0:  cmpq   %rbx, %rax
0x105b147f3:  je     0x105b1480d               ; swift_dynamicCastClassUnconditional + 77
0x105b147f5:  movq   0x8(%rax), %rax
0x105b147f9:  testq  %rax, %rax
0x105b147fc:  jne    0x105b147f0               ; swift_dynamicCastClassUnconditional + 48
0x105b147fe:  leaq   0x1da7d(%rip), %rax       ; "Swift dynamic cast failed"
0x105b14805:  movq   %rax, 0x88da4(%rip)       ; gCRAnnotations + 8
0x105b1480c:  int3   
0x105b1480d:  movq   %r14, %rax
0x105b14810:  popq   %rbx
0x105b14811:  popq   %r14
0x105b14813:  popq   %rbp
0x105b14814:  retq   
0x105b14815:  nopw   %cs:(%rax,%rax)

 

Community
  • 1
  • 1
eeb
  • 71
  • 7
  • 1
    What targets are your various files included in? I'm surprised you're not getting compiler errors without declaring Goal a public class. – jrturton Aug 03 '14 at 08:36
  • Until recently Swift didn't have access control. I did notice it was added in Beta 4 [Access Control](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html). According to the doc, the default is internal, which means: "Internal access enables entities to be used within any source file from their defining module, but not in any source file outside of that module. ". Are test classes considered part of the same module? – eeb Aug 03 '14 at 15:16
  • Not in my experience - I've been working on a core data project with unit tests and none of the app classes are available without being marked as public (in beta 4) – jrturton Aug 03 '14 at 15:18
  • As far as targets go, I added the Goal class to the Compile Sources for the test target. If I don't I can't compile the test class, as it says it can't find the goal class. – eeb Aug 03 '14 at 15:18
  • 1
    I don't think that's right. I think you need to leave it in the app target and mark it as public, and `import LifeList` at the top of each test case – jrturton Aug 03 '14 at 15:19
  • This worked!!! I noticed I don't have enough room here to add the answer. – eeb Aug 03 '14 at 15:48

2 Answers2

5

All credit goes to jrtuton for this. Is there some way to attribute the answer to him?

Here are the changes made:

  1. Removed the Goal class from the compile list for the test target.

  2. Added proper access modifiers to the Goal class:

    public class Goal: NSManagedObject {
    
        @NSManaged public var displayDesc: String
        @NSManaged public var motivation: String
        @NSManaged public var cratedDate: NSDate
        @NSManaged public var goalType: NSNumber
    
  3. Added a public init method:

    public init(entity: NSEntityDescription, insertIntoManagedObjectContext:   NSManagedObjectContext) {
        super.init(entity: entity, insertIntoManagedObjectContext:   insertIntoManagedObjectContext)
    }
    
  4. Imported the LifeList module in my test class:

    import LifeList
    
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
eeb
  • 71
  • 7
  • Don't worry about it. You can accept your own answer (after a while) and you've written it up pretty well. Have an upvote, and welcome to stack overflow! – jrturton Aug 03 '14 at 16:30
0

Try this:

@objc(CastExceptionTest)    // add this line
class CastExceptionTest: XCTestCase {
    ...
}
zisoft
  • 22,770
  • 10
  • 62
  • 73