测试与非测试中的Swift和CoreData Casting问题

我在Xcode 6上使用Swift和CoreData

我已经阅读了发行说明,并且已经看到了关于确保使用模块名称(应用程序名称)标记核心数据模型的问题,因此您可以在运行时将NSManagedObject为模型类型。

当我这样做时,我可以让应用程序正常运行(好!)。 但是,我的问题是,当我尝试测试相同的代码时,每当使用Swift dynamic cast failed错误(错误:()进行转换时,测试将始终崩溃。这使得我很难测试我的应用程序。

在为测试与运行构建应用程序时,我们使用的模块名称是否有任何影响?

提前感谢任何指针……

跟进:

这并不理想:如上所述,为了让Swift使用Core Data模型,您需要使用应用程序的名称来装饰类名。 这适用于构建应用程序,但测试在不同的应用程序名称下运行! 这意味着您需要进入数据建模器并将该类名从myAppname.myEntitymyAppnameTests.myEntity然后才能在测试使用或调用时按名称使用这些实体。

你是完全正确的,问题是当你运行App它正在寻找myAppname.myEntity ,当你运行Test时,它看起来像myAppnameTests.myEntity 。 我此时使用的解决方案(Xcode 6.1)是不填充CoreData UI中的Class字段,而是在代码中填写。

此代码将检测您是否作为App vs Tests运行,并使用正确的模块名称并更新managedObjectClassName

 lazy var managedObjectModel: NSManagedObjectModel = { // The managed object model for the application. This property is not optional... let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")! let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)! // Check if we are running as test or not let environment = NSProcessInfo.processInfo().environment as [String : AnyObject] let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest" // Create the module name let moduleName = (isTest) ? "StreakTests" : "Streak" // Create a new managed object model with updated entity class names var newEntities = [] as [NSEntityDescription] for (_, entity) in enumerate(managedObjectModel.entities) { let newEntity = entity.copy() as NSEntityDescription newEntity.managedObjectClassName = "\(moduleName).\(entity.name)" newEntities.append(newEntity) } let newManagedObjectModel = NSManagedObjectModel() newManagedObjectModel.entities = newEntities return newManagedObjectModel }() 

您需要在Entity.swift文件中添加一行,使其成为Objective-C类,如下所示:

 @objc(YourEntity) class YourEntity: NSManagedObject { ... } 

如果您的项目不包含任何Objective-c代码,我认为这是一个错误。 但是,您需要添加该行,直到此修复为止。

我是从这里学到的。

Youtubevideo于11:45

这是一个实际上对我有用的更新答案。 使用XCode 9.2

Ok, I figured it out! It's not exactly intuitive though. First, I had to comment out the @objc(EntityName) line in the NSManagedObject subclasses. Then I went back to the default Module defined in the xcdatamodeld (Current Project Module). Then I had to ensure that only my test classes (and NONE of the NSManagedObject subclasses or any other source files) were compiled as part of my test project (this was critical) and @testable import AppName in my test project class files. Now it never trys to use these classes in the AppNameTests module, only AppName and the test projects can only call public or internal code...therefore all is right in the universe, yay!