ManagedObjectModel 子类在 Swift 中不起作用
Posted
技术标签:
【中文标题】ManagedObjectModel 子类在 Swift 中不起作用【英文标题】:ManagedObjectModel subclass doesn't work in Swift 【发布时间】:2014-07-13 08:29:59 【问题描述】:总结一下我所做的:
创建了一个名为 2048 的项目。
创建了 NSManagedObject 的子类
class BestScore: NSManagedObject
@NSManaged var bestScoreModel: BestScoreModel
func update(score: Int)
self.bestScoreModel!.score = score
创建了 NSManagedObjectModel 的子类
class BestScoreModel: NSManagedObjectModel
@NSManaged var score: Int
在核心数据选项卡下创建了一个数据模型。将该文件命名为 2048.xcdatamodeld。添加了一个实体BestScoreModel,其属性为“score”,类型定义为Integer 16。另外,我还根据official document更新了实体的类为2048.BestScoreModel。
在控制器类中,我添加了以下变量
class HomeViewController: UIViewController
var bestScore: BestScore?
@lazy var context: NSManagedObjectContext =
let serviceName = NSBundle.mainBundle().infoDictionary.objectForKey("CFBundleName") as String
let modelURL = NSBundle.mainBundle().URLForResource(serviceName, withExtension: "momd")
let model = NSManagedObjectModel(contentsOfURL: modelURL)
if model == nil
println("Error initilizing model from : \(modelURL)")
abort()
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let storeURL = (urls[urls.endIndex-1]).URLByAppendingPathComponent("\(serviceName).sqlite")
var error: NSError? = nil
var store = coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error)
if store == nil
println("Failed to load store at \(storeURL) with error: \(error?.localizedDescription)")
abort()
var context = NSManagedObjectContext()
context.persistentStoreCoordinator = coordinator
return context
()
override func viewDidLoad()
super.viewDidLoad()
let entity: NSEntityDescription = NSEntityDescription.entityForName("BestScoreModel", inManagedObjectContext: context)
bestScore = BestScore(entity: entity, insertIntoManagedObjectContext: context)
bestScore.update(0)
应用程序构建成功,但是当我运行模拟器时,它抛出了以下异常
2014-07-13 00:56:59.944 2048[76600:4447122] -[NSManagedObject update:]: unrecognized selector sent to instance 0x10bc55d20
2014-07-13 00:56:59.948 2048[76600:4447122] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject update:]: unrecognized selector sent to instance 0x10bc55d20'
我对 ios 开发完全陌生,之前没有经验。我想把 Swift 作为一个在不学习 Objective-c 的情况下开始编写应用程序的机会。如果我配置错误,请告诉我。
感谢您的帮助。
PS:我从here 获得托管对象上下文的实现。非常感谢作者!
【问题讨论】:
【参考方案1】:NSManagedObjectModel
描述了应用程序中使用的所有实体的集合,通常没有理由对其进行子类化。
我建议您对实体和相应的实体使用相同的名称 托管对象子类。 (这也是 Xcode 在创建 Objective-C 托管对象子类时所做的)
Swift 托管对象子类(Xcode 还不能自动创建) 看起来就像这样:
class BestScore: NSManagedObject
@NSManaged var score: NSNumber
我使用 NSNumber
类型而不是 Int16
,因为 Swift 中的标量访问器方法托管
对象子类还不能正常工作,比较How to use Core Data Integer 64 with Swift Int64?。
然后将创建一个新的 BestScore 对象
bestScore = NSEntityDescription.insertNewObjectForEntityForName("BestScore", inManagedObjectContext: context) as BestScore
您可以直接访问它的属性,而不需要 update()
函数:
bestScore!.score = 0
附加说明: 将bestScore
属性定义为
隐式展开 可选的,因为您希望它在之后有一个值
viewDidLoad:
。这为您节省了以后的许多显式解包:
var bestScore: BestScore!
另外,如果应用程序再次运行,您可能需要重新加载 现有的最好成绩,而不是创建一个新的对象。 这意味着你必须先执行一个 fetch 请求,然后插入一个新的 仅当没有找到对象时:
let request = NSFetchRequest(entityName: "BestScore")
var error : NSError?
let result = context.executeFetchRequest(request, error: &error)
if !result || result.count == 0
// Error or no object found: create new one:
bestScore = NSEntityDescription.insertNewObjectForEntityForName("BestScore", inManagedObjectContext: context) as BestScore
bestScore.score = 0
else
// Use existing object:
bestScore = result[0] as BestScore
let score = bestScore.score.integerValue // NSNumber --> Integer
【讨论】:
抱歉回复晚了。我尝试了您的建议,现在我可以实例化托管对象上下文。但是在调用 NSEntityDescription.insertNewObjectForEntityForName() 时我仍然会遇到异常。线程异常为:thread #1: tid = 0x3b9e05, 0x00000001001e4dfa libswift_stdlib_core.dylib swift_dynamicCastClassUnconditional + 106, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
@Bing:我想我在发布之前测试了代码并且它有效。您是否在 Core Data 模型检查器中将实体的“Entity”和“Class”都设置为“BestScore”?
如果您的意思是 2048.xcdatamodeld 文件,是的,我已将实体重命名为 BestScore,并将类重命名为 2048.BestScore。我还尝试了作为 BestScore 的课程。两种情况都引发了相同的异常。 :( 我一定遗漏了一些东西,我觉得很难在 swift 中调试,虽然不确定 Objective-C
我使用我原来的方式(分别创建 NSEntityDescription 和 BestScore)并且成功了!但是现在当我尝试调用更新方法时,我面临另一个异常。按照您的建议直接更改分数值确实有效,但我仍然希望更新方法正常工作,因为这主要是为了学习目的。我得到的例外是Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject updateBestScore:withBestLevel:]: unrecognized selector sent to instance 0x10bf39e50'
非常感谢您的帮助!【参考方案2】:
尝试在.xcdatamodeld
文件中为实体指定模块名称。如需详细说明,请参阅"Using Swift with Cocoa and Objective-C (Swift 2.1)" 中的实现核心数据托管对象子类部分。
【讨论】:
以上是关于ManagedObjectModel 子类在 Swift 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
覆盖UIManagedDocument中的managedObjectModel
在 tableview 中显示图像时 managedObjectModel 错误指令
managedObjectModel:initWithContentOfURL 中的错误