LoginSignup
29
21

More than 5 years have passed since last update.

target/actionの代わりにclosureで処理を書けるマイクロライブラリを作りました

Last updated at Posted at 2016-04-16

その名もActionClosurable

どう使うか

以下のクラスおよびサブクラスがextensionで拡張されており、クロージャで処理を書くことができるようになっています。

UIControl, UIButton, UIGestureRecognizer, UIBarButtonItem and NSTimer

こんなふうに書けます。

let barButtonItem = UIBarButtonItem(title: "title", style: .Plain, closure: { _ in
    print("barButtonItem title")
})

button.on(.TouchDown) {
    $0.backgroundColor = UIColor.redColor()
}
button.on(.TouchUpOutside) {
    $0.backgroundColor = UIColor.whiteColor()
}
button.onTap {
    $0.enabled = false
    print($0)
}

self.gr = UITapGestureRecognizer? = UITapGestureRecognizer()
view.addGestureRecognizer(gr!)
gr?.onGesture { [weak self] in
    $0.removeTarget(nil, action: nil)
    self?.gr = nil
}

var i = 5
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, repeats: true) { [weak self] timer in
    print("timer", i)
    i -= 1
    if i <= 0 {
        timer.invalidate()
        self?.timer = nil
    }
}

なお、NSObjectを継承しているクラスであれば、好きなように拡張できます。めっちゃ簡単です。
どれだけ簡単かは、実際のソースを読んでいただければ分かるかと。


extension ActionClosurable where Self: UIButton {
    public func onTap(closure: Self -> Void) {
        registerClosure(closure) {
            self.addTarget($0, action: $1, forControlEvents: .TouchUpInside)
        }
    }
}

extension ActionClosurable where Self: NSTimer {
    public static func timerWithTimeInterval(ti: NSTimeInterval, repeats yesOrNo: Bool, closure: Self -> Void) -> Self {
        return registerClosure(closure) {
            let timer = Self.init(timeInterval: ti, target: $0, selector: $1, userInfo: nil, repeats: yesOrNo)
            return timer
        }
    }
}

こんな感じ。ね、簡単でしょ?

使った技について

ActionClosurableはマイクロライブラリなので、短いソースです。コアのロジックは実質40行足らず。
長々と解説するものでもないんで、今回のこだわりポイントをざっくり箇条書きで挙げます。

  • プロトコル指向
    • 常に型を Self で表現することで、指定したクロージャでは引数に対して柔軟に型推論が掛かります。たとえば、UIButtonを継承したHogeButtonを作ったら、クロージャの型も自動的に HogeButton -> Void になります。
  • @noescape
    • いいえ逃
    • registerClosure の中身で [weak self] とか書かなくていいの、気持ちいいですね。
  • objc_setAssociatedObject, objc_getAssociatedObject
    • プロトコルの中でストアドプロパティを保持できるようになる裏技。
    • actionを複数個設定しても動くように、ArrayやSetを噛ませて保持させようとしたら、どうも思ったタイミングでリリースされなくて結構ハマった。ここらへんの事情はそのうち単独の記事にしようかなと思います。

ほかにもライブラリ作ってますので良かったら是非

NotifwiftでNSNotification.userInfoをSwiftyに扱おう - Qiita

29
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
21