LoginSignup
9
9

More than 5 years have passed since last update.

RxSwiftでクロージャを減らす: APIリクエストのcompletionHandlerをObservableにしてみる

Posted at

RxSwiftを適用する箇所として、クロージャをObservableに切り替えるのが最近良いなと思ったので掲載。

APIクライアントからレスポンスを受けてUIを更新する操作はクロージャを使いますがこれをObservableを使って書き換えてみました。

Before

import UIKit

class ViewController: UIViewController {
    private var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        label = UILabel(frame: view.frame)
        label.numberOfLines = 10

        fetch(completion: { [weak self] data in
            guard let strongSelf = self else { return }
            strongSelf.label.text = String(data: data, encoding: .ascii)
            strongSelf.view.addSubview(strongSelf.label)
        })
    }

    private func fetch(completion: @escaping ((Data) -> Void)) {
        let request = URLRequest(url: URL(string: "https://www.google.com")!)
        URLSession.shared.dataTask(with: request, completionHandler: { data, _, error in
            guard
                error == nil,
                let data = data
            else { return }
            completion(data)
        }).resume()
    }
}

After

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    private var label: UILabel!
    private let disposeBag = DisposeBag()

    enum MyError: Error {
        case APIClientFailed
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        label = UILabel(frame: view.frame)
        label.numberOfLines = 10

        fetch().asObservable().subscribe(onNext: { [weak self] data in
            guard let strongSelf = self else { return }
            strongSelf.label.text = String(data: data, encoding: .ascii)
            strongSelf.view.addSubview(strongSelf.label)
        }).disposed(by: disposeBag)
    }

    private func fetch() -> Observable<Data> {
        return Observable<Data>.create { observer in
            let request = URLRequest(url: URL(string: "https://www.google.com")!)
            URLSession.shared.dataTask(with: request, completionHandler: { data, _, error in
                guard
                    error == nil,
                    let data = data
                else { return observer.on(.error(MyError.APIClientFailed)) }
                observer.on(.next(data))
                observer.on(.completed)
            }).resume()

            return Disposables.create()
        }
    }
}

こういう風に作っておくと、一度に2つ以上のエンドポイントにリクエストを送ってその内容をマージしたくなったり、リクエスト前後にバリデーションが必要になったりしたときにRxSwiftの能力を発揮して複雑性を増やさずにコードを書ける気がしています。

9
9
0

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
9
9