221
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

【RxSwift入門】普段使ってるこんなんもRxSwiftで書けるんよ

RxSwift取り入れたけどまだ慣れてない人向け
なんかのヒントになれば幸いです。

Delegate

RxSwift使ってたら自前Delegateclosureは作らなくなってくると思います

普通の書き方
class SampleViewController: UIViewController, SampleViewDelegate {
    @IBOutlet weak var view: SampleView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // MARK: SampleViewDelegate
    func sendMessage(message: String) {
        print("Did select : \(message)")
    }
}

class SampleViewDelegate {
    func sendMessage(message: String)
}

class SampleView: UIView {
    weak var delegate: SampleViewDelegate?

    private func didSelect() {
        delegate?.sendMessage("message")
    }
}
Rxを取り入れた書き方
import RxSwift
class SampleViewController: UIViewController {
    @IBOutlet weak var view: SampleView!

    override func viewDidLoad() {
        super.viewDidLoad()
        view.rx_message
            .subscribeNext { [ unowned view] message in
                print("Did select : \(message)")
            }
            .addDisposableTo(rx_disposeBag)
    }
}

class SampleView: UIView {    
    // ここでは`PublishSubject`を使っていますが、
    // イベントの取得だけでなく、値の保持をしたいなら`Variable`を使うのがいいです
    let rx_message = PublishSubject<String>()

    private func didSelect() {
        rx_message.on(.Next("message"))
    }
}

Delegate Extensionを作ってみる

RxSwiftの記述を参考に、DelegateメソッドをObserverで返せるようにしてみます
例としてUINavigationControllerのExtensionをあげます

extension UINavigationController {

    var rx_willShowViewController: Observable<(UIViewController, Bool)> {
        return rx_delegate.observe("navigationController:willShowViewController:animated:")
            .map { a in
                // 引数に渡したい値を返します
                return (a[1] as! UIViewController, a[2] as! Bool)
        }
    }
    var rx_didShowViewController: Observable<(UIViewController, Bool)> {
        return rx_delegate.observe("navigationController:didShowViewController:animated:")
            .map { a in
                // 引数に渡したい値を返します
                return (a[1] as! UIViewController, a[2] as! Bool)
        }
    }
}

RxSwiftに用意されてる便利なObserverたち

ここからは意外となんでもあるな、というものを紹介します。

RxSwiftは結構Observerが用意されています。
主によく使ったもののみの紹介とさせていただきます。ここにないのもたくさんあります。
コード書く際に、まずはObserverがないか試してみるといいと思います。

ボタンのタップイベント

普通の書き方
class SampleViewController: UIViewController {
    @IBOutlet weak var button: UIButton!
    private var flag = false

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(SampleViewController.onClickPushButton), forControlEvents: .TouchUpInside)
    }

    func onClickPushButton(sender: UIButton) {
        if flag {
            print("did tap")
        }
    }
}
Rxを取り入れた書き方
import RxSwift

class SampleViewController: UIViewController {
    @IBOutlet weak var button: UIButton!
    private var flag = false

    override func viewDidLoad() {
        super.viewDidLoad()
        button.rx_tap
            .filter {[unowned self] self.flag}
            .subscribeNext {
                print("did tap")
            }
            .addDisposableTo(button.rx_disposeBag)
    }
}

UIControlEventsもあります

Rxを取り入れた書き方
import RxSwift
class SampleViewController: UIViewController  {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        button.rx_controlEvent(UIControlEvents.TouchUpInside)
            .subscribeNext { [unowned self] in
                print("button TouchUpInside!")
            }
            .addDisposableTo(button.rx_disposeBag)
    }
}

NSNotificationCenter

普通の書き方
class SampleViewController: UIViewController {
    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "notificationObserve:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
    }

    func notificationObserve(notification: NSNotification) {
        print("notificationObserve : \(notification)")
    }
}
Rxを取り入れた書き方
import RxSwift
class SampleViewController: UIViewController {

    deinit {
        // rx_disposeBagは開放されるのでremoveの必要なし
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().rx_notification(AVPlayerItemDidPlayToEndTimeNotification, object: nil)
            .subscribeNext { [ unowned view] notification in
                print("rx_notification : \(notification)")
            }
            .addDisposableTo(rx_disposeBag)
    }
}

UIScrollView. contentOffset

普通の書き方
class SampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
    }

    func scrollViewDidScroll(scrollView: UIScrollView) {
        print("scrollViewWillBeginDragging \(scrollView.contentOffset)")
    }
}
Rxを取り入れた書き方
class SampleViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rx_contentOffset
            .subscribeNext { [weak self] contentOffset in
                // contentOffset値の変化時に取得
                print("rx_contentOffset : \(contentOffset)")
            }
            .addDisposableTo(rx_disposeBag)
    }
}

Gesture

普通の書き方
class SampleViewController: UIViewController  {

    @IBOutlet weak var view: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer(target: self, action: "tapGesture:")
        view.addGestureRecognizer(tapGesture)
    }

    func tapGesture(gesture: UIGestureRecognizer) {
        print("gestureのtapイベントを取得")
    }
}
Rxを取り入れた書き方
class SampleViewController: UIViewController  {

    @IBOutlet weak var view: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer()

        tapGesture.rx_event
            .map(void) // 引数使わない場合はmapしてしまう
            .subscribeNext {
                print("gestureのtapイベントを取得")
            }
            .addDisposableTo(view.rx_disposeBag) // viewが持つ`rx_disposeBag`を使うと開放時にわかりやすい

        view.addGestureRecognizer(tapGesture)
    }
}

NSURLSession

多くなってきたのでちょっと駆け足で。
↓取得してObserverにして返すのも便利です

private func getData() -> Observable<NSData> {
    let url = NSURL(string: "https://xxxx")!
    return NSURLSession.sharedSession()
        .rx_data(NSURLRequest(URL: url))
        .take(1)
}

UISlider

slider.rx_value.asObservable()
    .subscribeNext { value in
        print("Sliderの値変更時に\(value)取得")
    }
    .addDisposableTo(slider.rx_disposeBag)

以上になります。
書き慣れてない文章でごめんなさい。
自分もまだまだ人のを真似ることしかできないので知らない部分だらけです。
思いついたらどんどん足していきます。

なにかありましたらお気軽にご教授ください。
なにかの参考にさればさいわいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
221
Help us understand the problem. What are the problem?