こんにちは=)私は(本質的に)次のことをする必要があるデザインの問題に直面しました:
プロトコルに準拠する_viewWillAppear:
_のUIViewController
サブクラスに少しコードを挿入したいMyProtocol
。コードで説明:
_protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController where Self: MyProtocol //<-----compilation error
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
_
ここでの主な問題は、UIVIewController
拡張機能で2つのことを行う必要があることです。
MyProtocol
およびUIViewController
APIの両方を呼び出すviewWillAppear:
_をスウィズルできるようにUIViewController
メソッドinitialize()
をオーバーライドしますこれらの2つの機能は互換性がないようです(Swift 3以降)。
extension UIViewController where Self: MyProtocol
_)extension MyProtocol where Self: UIViewController
_を追加できますが、メソッドをオーバーライドできませんプロトコル拡張のクラスから。つまり、スウィズリングに必要なpublic override class func initialize()
を実行できません。それで、私が直面しているこの問題に対してSwiftyソリューションを提供できる誰かがいるのではないかと思っていましたか? =)
前もって感謝します!!
まあ、これまでのところ、本当に満足のいく方法を見つけることはできませんでしたが、この特定の問題に対して結局何をしたかを投稿することにしました。簡単に言えば、ソリューションは次のようになります(元のサンプルコードを使用)。
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController //------->simple extension on UIViewController directly
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//------->only run when self conforms to MyProtocol
if let protocolConformingSelf = self as? MyProtocol {
//invoke APIs from
protocolConformingSelf.protocolFunction() // MyProtocol APIs
let viewLoaded = protocolConformingSelf.isViewLoaded // UIViewController APIs
}
}
}
欠点:
UIViewControllers
プロトコルに準拠するもののみを検証する場合でも、スウィズリングメソッドが呼び出され、ALL MyProtocol
で有効になります。私はそれが同じような状況に直面している他の誰かを助けることを願っています=)
あなたは解決策の近くにいました。それを逆にするだけです。 UIViewControllerの一部である場合にのみプロトコルを拡張します。
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension MyProtocol where Self: UIViewController {
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}