序
NSFetchRequest
にGenericsが導入されてキャストの嵐から解放されて久しいですが、どうもGenericsの使い方が全く分かっていないサンプルコードがあふれかえっているようなので、ここで改めて正しいNSFetchRequest
の使い方を紹介しておきます。
エンティティサンプル
エンティティは特に何でもよいのでごく単純な以下のものを使います。
エンティティ名はクラス名と同じです。
class Company: NSManagedObject {
@NSManaged var name: String
}
悪い例
僕が怒り心頭の悪い例はこちらです。
func fetchAllCompanies() -> [Company] {
let context: NSManagedObjectContext = ...
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Company")
do {
guard let companies = try context.fetch(request) as? [Company] else {
fatalError("Can not cast fetch result.")
}
return companies
}
catch {
print("Fetch error:", error)
return []
}
}
NSFetchRequest
の型パラメータをNSFetchRequestResult
としています。
これが完全な誤りです。
使い方を誤っているために本来必要ない[Company]
へのダウンキャストの必要性が発生しています。
正しい例
こちらが正しい使い方です。
func fetchAllCompanies() -> [Company] {
let context: NSManagedObjectContext = ...
let request = NSFetchRequest<Company>(entityName: "Company")
do {
return try context.fetch(request)
}
catch {
print("Fetch error:", error)
return []
}
}
NSFetchRequest
の型パラメータにCompany
を用いることで、NSManagedObjectContext#fetch(_:)
の戻り値の型は[Company]
に確定します。
ダウンキャストは不要なのです。
おわりに
某所でNSFetchRequest<NSFetchRequestResult>
を使っているサンプルを発見してしまい、なんとなく検索してみると同様のサンプルがいまだに数多く残っていたので怒りに任せて書きました。
簡単にするための機構をあざ笑うかのようなこの所業はさすがに見逃せなく、煽りタイトルとさせていただきました。
僕はただ、正しい使い方を広めたかっただけです。
罵りは甘受します。