Swift + Core Data Code Generation で Objective-C からの呼び出しでクラッシュするケース
部分的に Swift で書き直しているプロジェクトで起きたケース。
.xcdatamodeld のエンティティ設定で Core Data の Code Generation を Objective-C から Swift に変更した後 Objective-C からの呼び出しでクラッシュ
まず Objective-C と Swift の Core Data Code Generation については以下を参照
Swift ソースを自動生成した場合、class func fetchRequest
が @nonobjc
になっているのに注意。
クラスメソッドとしては以下の様にiOS 10以降で +fetchRequest
が利用可能になっているが、
// Objective-C @interface NSManagedObject : NSObject + (NSFetchRequest*)fetchRequest API_AVAILABLE(macosx(10.12),ios(10.0),tvos(10.0),watchos(3.0)); @end
// Swift open class NSManagedObject : NSObject { @available(iOS 10.0, *) open class func fetchRequest() -> NSFetchRequest<NSFetchRequestResult> }
呼ばれる実装の実態として自動生成によりサブクラス(モデルクラス)に実装されている fetchRequest
メソッドが必要となるため、以下の様に Objective-C でメソッド呼び出しを行った場合に自動生成されたメソッドが呼ばれず意図した NSFetchRequest
が取得出来ずクラッシュする模様。
// Objective-C
NSFetchRequest<Model *> *request = [Model fetchRequest];
対応パターン
1.
Objective-C ソースを生成する様に設定し Objective-C と Swift から +fetchRequest
を利用する。
// Objective-C
NSFetchRequest<Model *> *request = [Model fetchRequest];
// Swift let request: NSFetchRequest<Model> = Model.fetchRequest
2.
Swift ソースを生成する様に設定した場合、Objective-C からの呼び出しは
-fetchRequestWithEntityName:
メソッドを使いエンティティ名を指定して fetchRequest
を作成する様に実装する。
// Objective-C NSFetchRequest<Model *> *request = [NSFetchRequest fetchRequestWithEntityName:@"Model"];
// Swift let request: NSFetchRequest<Model> = Model.fetchRequest
3.
Swift ソースを生成する様に設定し Swift からしか呼び出さない様にする。
// Swift let request: NSFetchRequest<Model> = Model.fetchRequest
Swift への移行が進めば3番になっていくかも知れないがまずは1番か2番だろう。