Swiftのデリゲートメソッドでデフォルト引数ぽく書く方法

概要

コードレビューの時にデリゲートメソッドの部分で指摘を受けて修正しようと思ったのですが、

なかなかすぐに思いつかなかったので記事として残してみることにしました。

自分への備忘録です。

記事にまとめてみると復習の意味でも結構いい勉強になりました。

問題となっているポイントについて

Swiftで書いているときにprotocolのメソッドで引数にデフォルト値を設定したくなる時があると思います。

例えば、こんな感じのコードですね。

protocol CustomContentViewDelegate: AnyObject {
    func customContentViewDidTouchUp(_ view: CustomView, text: String? = nil) // コンパイルエラー
}

現状の仕様だとこのようにtext: String? =nilというのはprotocolでは持てない仕様である。

ですが仮にこれができた場合にはdelegateを呼び出し側で

protocol CustomContentViewDelegate: AnyObject {
    func customContentViewDidTouchUp(_ view: CustomView, text: String? = nil)
}

class CustomView: UIView {
    weak var delegate: CustomContentViewDelegate?

    func sampleMethod() {
        // デフォルト引数発動
        delegate?.customContentViewDidTouchUp(self) 
        // 引数指定
        delegate?.customContentViewDidTouchUp(self, text: "テスト実装")
    }
}

という風にtextの引数を省略できて保守性が上がるというわけです。

この命題について考えたいと思います。

回答

いきなり回答に入りますがextensionでprotocolを拡張すれば言い訳です。

protocol CustomContentViewDelegate: AnyObject {
    func customContentViewDidTouchUp(_ view: CustomView, text: String?)
}

// protocol extension でデフォルト引数を設定する
extension CustomContentViewDelegate {
    func customContentViewDidTouchUp(_ view: CustomView) {
        customContentViewDidTouchUp(view, text: nil)
    }
}

class CustomView: UIView {
    weak var delegate: CustomContentViewDelegate?

    func sampleMethod() {
        // デフォルト引数発動
        delegate?.customContentViewDidTouchUp(self) 
        // 引数指定
        delegate?.customContentViewDidTouchUp(self, text: "テスト実装") 
    }
}

これも一つのprotocol extensionの使い方かなと思い記事にしてみました。

ただ、コードレビューで指摘された時だと実際どんな風にしたら丁寧で見易いようになるかを2~3時間ぐらいかかりましたので

このような指摘をする場合には「protocol extensionで実装したらデフォルト引数ぽくなりますのでいいと思いますよ」と

指摘して頂ければすんなり解決した話しだったりします。