メソッドチェーンで遊ぶ


UILabelに愛してると表示するとき

        let label = UILabel()
        label.frame.origin = CGPoint(x: 100, y: 100)
        label.frame.size = CGSize(width: 200, height: 50)
        label.backgroundColor = .red
        label.layer.cornerRadius = 25
        label.clipsToBounds = true
        label.text = "i love you"
        label.textColor = .white
        label.textAlignment = .center
        view.addSubview(label)

labelって描くのめんどくさいとふと思いメソッドチェーンぽく描いて遊んでみた。

    let label = UILabel().chain
        .origin(x: 100, y: 100)
        .size(width: 200, height: 50)
        .backgroundColor(.red)
        .cornerRadius(25)
        .clipsToBounds()
        .text("i love you")
        .textColor(.white)
        .alignment(.center)
        .object()
    view.addSubview(label)

やっぱりメソッドチェーンはxcodeの補完でサクサクかけて楽チンだと思う。

実装


protocol Chainable {}

extension Chainable where Self: UIView {
    var chain: ChainMaker<Self> {
        return ChainMaker(self)
    }
}

class ChainMaker<T> {

    private var base: T
    init(_ base: T) {
        self.base = base
    }

    func object() -> T {
        return base
    }
}

extension UIView: Chainable {}

とりあえずこれでUIViewがchainプロパティーを持つのでChainMaker(仮)を拡張していく
object()メソッドはキャスト用で最後に使う。


extension ChainMaker where T: UIView {

    func origin(x: CGFloat, y: CGFloat)  -> ChainMaker<T> {
        base.frame.origin = CGPoint(x: x, y: y)
        return self
    }

    func size(width: CGFloat, height: CGFloat)  -> ChainMaker<T> {
        base.frame.size = CGSize(width: width, height: height)
        return self
    }

    func backgroundColor(_ color: UIColor) -> ChainMaker<T> {
        base.backgroundColor = color
        return self
    }

    func clipsToBounds() -> ChainMaker<T> {
        base.clipsToBounds = true
        return self
    }

    func cornerRadius(_ radius: CGFloat) -> ChainMaker<T> {
        base.layer.cornerRadius = radius
        return self
    }
}

extension ChainMaker where T: UILabel {

    func text(_ text: String) -> ChainMaker<T> {
        base.text = text
        return self
    }

    func textColor(_ color: UIColor) -> ChainMaker<T> {
        base.textColor = color
        return self
    }

    func alignment(_ alignment: NSTextAlignment) -> ChainMaker<T> {
        base.textAlignment = alignment
        return self
    }
}

追記

クロージャーで描いた方がスッキリしてていいですね

extension Chainable where Self: UIView {

    func chain(_ closure: (ChainMaker<Self>)->(ChainMaker<Self>)) -> Self {
        let maker = ChainMaker(self)
        return closure(maker).object()
    }
}
        let label = UILabel().chain { $0
            .origin(x: 100, y: 100)
            .size(width: 200, height: 50)
            .backgroundColor(.red)
            .cornerRadius(25)
            .clipsToBounds()
            .text("i love you")
            .textColor(.white)
            .alignment(.center)
        }
        view.addSubview(label)