私のアプリには、詳細ビューコントローラー用のプロトコルがあり、viewModel
プロパティが必要であると述べています。
protocol DetailViewController: class {
var viewModel: ViewModel? {get set}
}
また、プロトコルを実装するいくつかの異なるクラスがあります。
class FormViewController: UITableViewController, DetailViewController {
// ...
}
class MapViewController: UIViewController, DetailViewController {
// ...
}
私のマスタービューコントローラーには、UIViewController
プロトコルを実装する任意のDetailViewController
サブクラスに設定できるプロパティが必要です。
残念ながら、これを行う方法に関するドキュメントは見つかりません。 Objective-Cでは、それは簡単です。
@property (strong, nonatomic) UIViewController<DetailViewController>;
Swiftこれを行う構文はありません。最も近いのは、クラス定義でジェネリックを宣言することです。
class MasterViewController<T where T:UIViewController, T:DetailViewController>: UITableViewController {
var detailViewController: T?
// ...
}
しかし、「クラス 'MasterViewController'はスーパークラスの必要なメンバーを実装していません」というエラーが表示されます
SwiftはObjective-Cと同じように簡単に実行できるはずですが、どうすればよいかを示唆するものはどこにも見つかりません。
Swift 4以降、これを実行できるようになりました。
Swift 4の実装 SE-0156 (クラスとサブタイプの存在)。
このObjective-C構文に相当するもの:
@property (strong, nonatomic) UIViewController<DetailViewController> * detailViewController;
Swift 4では次のようになります。
var detailViewController: UIViewController & DetailViewController
基本的に、変数が準拠する1つのクラスと、変数が実装するN個のプロトコルを定義できます。詳細については、リンク先のドキュメントを参照してください。
(空の)拡張をUIViewController
に追加し、空の拡張とdetailViewController
の合成プロトコルを使用してDetailViewController
属性を指定することで、そこに到達できると思います。このような:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
これで、UIViewController
のすべてのサブクラスがプロトコルUIViewControllerInject
を満たします。次に、単に:
typealias DetailViewControllerComposed = protocol<DetailViewController, UIViewControllerInject>
class MasterViewController : UITableViewController {
var detailViewController : DetailViewControllerComposed?
// ...
}
しかし、これは特に「自然」ではありません。
===編集、追加===
実際、提案されたDetailViewController
を使用してUIViewControllerInject
を定義すると、少し良くなる可能性があります。そのような:
protocol UIViewControllerInject {}
extension UIViewController : UIViewControllerInject {}
protocol DetailViewController : UIViewControllerInject { /* ... */ }
これで、明示的に何かを作成する必要はなく(my DetailViewControllerComposed
)、detailViewController
のタイプとしてDetailViewController?
を使用できます。
別の方法は、プロトコルを実装する適切なUIKitビューコントローラに中間ベースクラスを導入することです。
class MyUIViewControler : UIViewController, DetailViewController ...
class MyUITableViewController : UITableViewController, DetailViewController ...
次に、UIKitではなく、これらのView ControllerからView Controllerを継承します。
これも自然なことではありませんが、GoZonerが提案したように、すべてのUIViewControllers
がUIViewControllerInject
プロトコルを満たすことを強制するわけではありません。