Delegate
Swift
observer
RxSwift
Swift2.0

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

More than 1 year has passed since last update.

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)


以上になります。

書き慣れてない文章でごめんなさい。

自分もまだまだ人のを真似ることしかできないので知らない部分だらけです。

思いついたらどんどん足していきます。

なにかありましたらお気軽にご教授ください。

なにかの参考にさればさいわいです。