Qiitaに書いたやつ

Swift5.1 dynamicMemberLookup^KeyPathを使ってSwiftにKotolinのapplyを実装する

XcodeiOSKotlinSwift
2019年10月04日

デモ

final class ViewController: UIViewController {
    override func loadView() {
        view = UILabel().apply { $0
            .text("Apply Swift")
            .textAlignment(.center)
            .textColor(.white)
            .font(.boldSystemFont(ofSize: 24))
            .backgroundColor(.black)
        }
    }
}
Simulator Screen Shot - iPhone 8 - 2019-10-10 at 22.43.54.png

私以外にもKotolinのapplyをSwiftでもやりたいと思ったことのある人はいるでしょう。 例えば以下のようにUILabelを定義する場面を考えます。

let label: UILabel = {
   let it = UILabel()
   it.text = "label.." 
   return it
}()

以前までは、以下のようなプロトコルを定義することで

protocol Applicatable {}

extension Applicatable {
  func apply(_ closure: ((Self) -> ())) -> Self {
        closure(self)
        return self
    }
}

extension NSObject: Applicatable {}

それっぽく実装することができました。

let label = UILabel().apply { it in
   it.text = "label.."
}

しかし言語の進化により、もっとKotolinのapplyに近づけることができるようになりました。 つい先日DuctTapeというライブラリが公開されたのをきっかけにそれが可能になってたことを知りました。(Swiftのキャッチアップに遅れぎみです)

dynamicMemberLookup

Swift4.2で追加された機能ですが

@dynamicMemberLookup
struct StringMaker {
    subscript(dynamicMember value: String) -> String {
        return value
    }
}

let maker = StringMaker()
debugPrint(maker.id) // String: id
debugPrint(maker.name) // String: name

Swift5.1からKeyPathを使えるようになったみたいです。

@dynamicMemberLookup attribute requires ‘xxx’ to have a ‘subscript(dynamicMember:)’ method that accepts either ‘ExpressibleByStringLiteral’ or a keypath

これを使って参考ライブラリをパクりつつインターフェースの変更を40行程度実装すると

      let label = UILabel().apply { $0
            .text("Apply Swift")
            .textAlignment(.center)
            .textColor(.white)
            .backgroundColor(.black)
        }

debugPrint(label.text) // Optional(Apply Swift)

上記のような実装をすることができました。 一応ソースはGistに公開しておきます。

https://gist.github.com/churabou/7243d4ac9121a56513bb16023e3698f7

同じタグの投稿

2020 churabou