24
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SwiftでNSManagedObjectのSubclassを使う時の罠と回避策

Last updated at Posted at 2014-07-31

はじめに

Xcode6 beta4 で、SwiftでCoreDataを利用したいときに、
NSManagedObjectのSubclassを使うといろいろ罠があるので共有します。
何かしらのバグっぽいので、いずれ不要になることを願います。

断片的に色々情報がありますが、最終的には以下の記事が参考になりました。
http://www.sep.com/sep-blog/2014/06/23/a-c-developer-learns-swift-part-1-core-data/

@objc(HogeEntity) の おまじない


【更新】2014/8/2
これは付けないほうが良さそうです。
SwiftでNSManagedObjectのSubclassを使う場合は、対応Class名にモジュール名のPrefixを付ける


まず、 NSManagedObject の Subclassは @objc(EntityClass) を付けておきます。

@objc(ChildEntity)
class ChildEntity: NSManagedObject {
    @NSManaged var identity: String
    @NSManaged var name: String?
    @NSManaged var birthday: NSDate?
    @NSManaged var sex: Int
    @NSManaged var imageFile: String?
}

以下のように書いてもOKです。 ←嘘でした。

@obj class ChildEntity: NSManagedObject {
...

2014/8/2 追記

@objc(MyClass)
class MyClass ...

と書くのと、

@objc class MyClass

と書くのではどうやら意味が少し変わるようです。
少なくとも前者は名前空間が (root).MyClass になるようで、
従来のObjectiveCの interface MyClass と衝突します。
が、後者では衝突しないようです。

以下の内容も 前者の書き方 だと両方のコードで動きました
後者の書き方だと一見動くけど何かハマるだけのようです。

そして最終的には、下記のやり方の方がオススメで、この方法でも下記の両方のコードが動きました。
SwiftでNSManagedObjectのSubclassを使う場合は、対応Class名にモジュール名のPrefixを付ける

家と会社のPCで動作が違うような気がしないでもない、、、とにかくハマりやすいので気をつけましょう。


Entityを作る時

何故かうまくいかない書き方

以下のように書くとCastに失敗するようでエラーになりました。
NSManagedObject の Instanceは取得できているのですが、そこからのCastが失敗します。

    let obj = NSEntityDescription.insertNewObjectForEntityForName("ChildEntity", inManagedObjectContext: mainContext)
    let child = obj as ChildEntity

上手くいく書き方

こうすると上手く行きました。明示的に Class と CoreData Entity を結びつけてしまうわけですね。
本来こんな必要はなさそうですが、とりあえず今はしょうがないのかな。。

    let entity = NSEntityDescription.entityForName("ChildEntity", inManagedObjectContext: mainContext)
    let child = ChildEntity(entity: entity, insertIntoManagedObjectContext: mainContext)

Fetchする時

何故か上手くいかない書き方

こう書くとやはり Castするところでnilになってしまいます。 as?as にすると当然エラーになります。

    func loadAll() -> [ChildEntity]? {
        let request = NSFetchRequest(entityName: "ChildEntity")
        var array = mainContext.executeFetchRequest(request, error: nil)
        return array as? [ChildEntity]
    }

何故か上手くいく書き方

そしてこれが何故か上手くいく書き方です。 array:NSArray というのがおまじないです。
何がなんだかもうわかりません。

    func loadAll() -> [ChildEntity]? {
        let request = NSFetchRequest(entityName: "ChildEntity")
        let array: NSArray = mainContext.executeFetchRequest(request, error: nil)
        return Array.bridgeFromObjectiveC(array)
    }

(2014/8/6追記)beta5だと上手くいく書き方

beta5だと Fetchの結果をNSArrayにしてから、array as [T]で良いようです。
あと、 Array.bridgeFromObjectiveC は無くなったようですね。

    func loadAll() -> [ChildEntity]? {
        let request = NSFetchRequest(entityName: "ChildEntity")
        let array: NSArray = mainContext.executeFetchRequest(request, error: nil)
        return array as? [ChildEntity]
    }
24
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?