Swiftのoptional funcでenumを使いたい時

protocolについて

まずswiftにはprotocolが用意されている。例えばUIKit系のクラスではよくdelegateやdataSourceが用意されていて、他のクラスに処理を委譲する設計になっている。delegateやdataSourceを継承したクラスはその処理を書かなければならない。

class HogeViewController: UIViewController, UITableViewDataSource {
    // UITableViewDataSource内で定義された関数をこのクラス内で実装しなければいけない
    // 実装しなければコンパイルエラーが起こる
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {}
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
}

optional funcを定義する

上でprotocolについて説明したが、継承しても実装しなくても大丈夫なようにもできる。optionalを修飾子としてつければ良い。

// optional funcを定義するにはそれとprotocolに@objc属性をつけなければいけない
@objc protocol HogeDelegate {
    @objc optional func doSomething()
}

optional funcにenumを使う

通常のprotocol(@objc属性がついてない)ものであればenumを使ってもエラーにはならないが、@objc属性がついているものはエラーになってしまう。

enum MyType {
    case A
    case B
}

@objc protocol HogeDelegate {
    @objc optional func didChange(type: MyType) // Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C
}

これの解決策はenumにも@objc属性をつける。ただし、注意点としてそのenumにはIntを継承させなければいけない。

@objc enum MyType: Int {
    case A 
    case B 
}

@objc protocol HogeDelegate {
    @objc optional func didChange(type: MyType)
}

まとめ

optional funcにenumを使いたければ、protocolとenum@objc 属性をつければ良い。 コード例は抽象的だが、自分でカスタムUIクラスなど作るときに使えると思う。

最後にswiftにはenumやprotcolといった魅力的な機能があるが、それにわざわざ@objc 属性を付けるのは少し面倒くさいと思ってしまった。