ManagedObjectModel子类在Swift中不起作用

时间:2014-07-13 08:29:59

标签: core-data swift nsmanagedobject nsmanagedobjectmodel

总结我所做的事情:

  1. 创建了一个名为2048的项目。

  2. 创建了NSManagedObject的子类

    class BestScore: NSManagedObject {
        @NSManaged var bestScoreModel: BestScoreModel
        func update(score: Int) {
            self.bestScoreModel!.score = score
        }
    }
    
  3. 创建了NSManagedObjectModel的子类

    class BestScoreModel: NSManagedObjectModel {
        @NSManaged var score: Int
    }
    
  4. 在Core Data选项卡下创建了一个数据模型。将文件命名为2048.xcdatamodeld。添加了一个具有一个属性“score”的实体BestScoreModel,并将类型定义为Integer 16.此外,我还根据official document将实体的类更新为2048.BestScoreModel。

  5. 在控制器类中,我添加了以下变量

    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)
        }
    }
    
  6. 应用程序已成功构建,但是当我运行模拟器时,它会抛出以下

    的异常
        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获得了托管对象上下文的实现。非常感谢作者!

2 个答案:

答案 0 :(得分:2)

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!

此外,如果应用程序第二次运行,您可能需要重新加载 现有的最佳分数,而不是创建新对象。 这意味着您必须首先执行获取请求,然后插入新的 只有在没有找到时才对象:

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

答案 1 :(得分:0)

尝试在.xcdatamodeld文件中指定实体的模块名称。有关详细说明,请参阅"Using Swift with Cocoa and Objective-C (Swift 2.1)"一书中的实施核心数据管理对象子类部分。