2016-11-01 13 views
4

私は複数のNSFetchedResultsControllersをラップし、デリゲートになり、インデックスパスを自身のデリゲートに戻す前に変換するSwiftクラスを持っています。このクラスは、同じプロトコルに準拠している限り、異なるエンティティを返すNSFetchedResultsControllersを受け取ることができます。 Swift 3にアップグレードするとき、私はコンパイルするために同じ機能を得ることができません。Swiftの複数のNSFetchedResultsController 3

たとえば、2つの異なるEntityタイプを返す2つのNSFetchedResultsControllersをラップして、単一のtableViewに表示したいとします。どちらのCoreDataエンティティは以下のプロトコル

protocol ManagedObjectDisplayType : NSFetchRequestResult { 
    var id:String { get } 
    func friendlyName() -> String 
} 

に準拠問題は今NSFetchedResultsControllersは二つのコントローラのタイプが異なるので、私は私のラッパークラスに渡すことができNSFetchedResultsControllerの具体的な種類が存在しない、汎用的であるということです。例えば

let entity1Request = NSFetchRequest<Entity1>(entityName: entityName) 
let entity1Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 
let entity2Request = NSFetchRequest<Entity2>(entityName: entityName) 
let entity2Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity2Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 

私は、私は次のエラーを取得するこれを行うと:総理にかなっている「サポートされていないプロトコルのNSFetchRequestResult」に準拠した具体的なタイプとして 『ManagedObjectDisplayType』を使用します」。

しかし、私がやろうとしていることをやり遂げるための別の方法はわかりません。

+0

'ManagedObjectDisplayType'が、それに準拠したプロトコルではなく、エンティティの抽象スーパークラスであればどうでしょうか?それはプロトコル指向ではありませんが、 'ManagedObjectDisplayType'がコンクリートになります。 – theMikeSwan

答えて

3

これは...

enter image description here

型消去のための仕事のように見えます!

Swiftにタイプ消去について書かれたものがたくさんありますが、これは興味深い状況です。私はあなたのさまざまなタイプの複数NSFetchedResultsControllerを保持することができますオブジェクトを作成する問題を抱えていると仮定しています。問題は、Swift(現在のバージョンでは)が必要なメモリを正しく割り当てるための具体的な型を必要としていることです。標準ライブラリや他の場所でのこれに対する標準的な解決方法は、基になる型を隠すボックスを作成することです。この場合、AnyFetchedResultsControllerクラスは実質的に以下の数字のコンクリートタイプ(NSFetchedResultsController<T> where T: ManagedObjectDisplayType)を消去します。

class AnyFetchedResultsController: CustomDebugStringConvertible 
{ 
    var descImpl:() -> String 
    var performImpl:() throws ->() 

    init<T>(_ controller: NSFetchedResultsController<T>) where T: ManagedObjectDisplayType {  
     descImpl = { controller.debugDescription } 
     performImpl = { try controller.performFetch() } 
    } 

    func performFetch() throws { 
     try performImpl() 
    } 

    var debugDescription: String { 
     return "wrapping \(descImpl())" 
    } 
} 

let entity1Request = NSFetchRequest<Entity1>(entityName: "Foobar") 
let entity1Frc = NSFetchedResultsController<Entity1>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 
let entity2Request = NSFetchRequest<Entity2>(entityName: "Barfoo") 
let entity2Frc = NSFetchedResultsController<Entity2>(fetchRequest: entity2Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 


let frcs: [AnyFetchedResultsController] = [AnyFetchedResultsController(entity1Frc), AnyFetchedResultsController(entity2Frc)] 

今、あなたはこれらのフェッチ結果コントローラを格納する方法を持っていることを、あなたは基礎となるNSFetchedResultsControllerに呼び出す必要があります任意のメソッドを追加AnyFetchedResultsControllerクラスを肉付けする必要があります。

私はそれが理にかなっていると思います。さらなる質問がある場合は戻ってください!AnyFetchedResultsController.initため

編集

original署名:

init<T, U: NSFetchedResultsController<T>>(_ controller: U, _ managedObjectType: T? = nil) where T: ManagedObjectDisplayType 

はかなり複雑で、いくつかのコンパイルエラーを修正する必要があるように見えたダミーmanagedObjectTypeパラメータを持っていました。しかし、私はちょうどより単純なことを発見しました。

init<T>(_ controller: NSFetchedResultsController<T>) where T: ManagedObjectDisplayType 

(これも上記と同様)が同様に機能するようです。

2

私はあなたがこのようなEntity1何かの宣言を持っていると仮定し

実際の具象クラスの代わりManagedObjectDisplayType

を使用します。次に

class Entity1 : NSManagedObject, ManagedObjectDisplayType { 
    var id:String { 
     return "42" 
    } 

    func friendlyName() -> String { 
     return "foobar" 
    } 

} 

代わりの

let entity1Request = NSFetchRequest<Entity1>(entityName: entityName) 
let entity1Frc = NSFetchedResultsController<ManagedObjectDisplayType>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 

あなたが

を持っているでしょう
let entity1Request = NSFetchRequest<Entity1>(entityName: entityName) 
let entity1Frc = NSFetchedResultsController<Entity1>(fetchRequest: entity1Request, managedObjectContext:mainManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 

これは少なくともコンパイルします。

+0

提案してくれてありがとうございますが、具体的なタイプにすることを余儀なくされているので、これは問題を解決しません。私は以下のDave Westonsの解決策が質問によく答えると思う –

関連する問題