RxSwift를 사용하여 WKWebView의 로딩 프로세스를 잘 느낍니다.

17455 단어 iOSSwiftRxSwift

개요


  • WKWebView의 로딩 처리 (프로그레스 바의 UI 갱신이나 NavigationBar의 Title의 변경 등을 좋은 느낌으로 RxSwift로 쓴다

  • 이미지





    샘플 리포지토리


  • htps : // 기주 b. 코 m / 료 타카 하시 / W 쿠 ぇ b ぃ ぃ 에 wRx

  • 환경


  • Xcode 9.4
  • Swift 4.1
  • RxSwift 4.2
  • RxCocoa 4.2
  • RxOptional 3.5.0

  • 환경 구축



    Podfile
      pod 'RxSwift'
      pod 'RxCocoa'
      pod 'RxOptional'
    

    화면




    ViewController
    WKWebView를 포함한 ViewController






  • 버튼을 누르면 WKWebView를 포함 된 ViewController로 전환

  • 구현해 간다



    우선, Swift의 observer를 사용한 패턴으로 구현



    WKWebViewController.swift
    import UIKit
    import WebKit
    
    class WKWebViewController: UIViewController {
        @IBOutlet weak var webView: WKWebView!
        @IBOutlet weak var progressView: UIProgressView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupWebView()
        }
    
        private func setupWebView() {
            webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
            webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
    
            let url = URL(string: "https://www.google.com/")
            let urlRequest = URLRequest(url: url!)
            webView.load(urlRequest)
            progressView.setProgress(0.1, animated: true)
        }
    
        deinit {
            webView?.removeObserver(self, forKeyPath: "loading")
            webView?.removeObserver(self, forKeyPath: "estimatedProgress")
        }
    
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            if keyPath == "loading" {
                UIApplication.shared.isNetworkActivityIndicatorVisible = webView.isLoading
                if !webView.isLoading {
                    progressView.setProgress(0.0, animated: false)
                    navigationItem.title = webView.title
                }
            }
            if keyPath == "estimatedProgress" {
                progressView.setProgress(Float(webView.estimatedProgress), animated: true)
            }
        }
    }
    
  • 화면을 열면 google.com가로드됩니다.
  • 로드에 따라 다음 값이 변경됩니다.
  • 진행률 막대 값
  • 진행률 표시 줄 표시/숨기기
  • ActivityIndicator 표시 및 숨기기

  • 로드가 완료되면 NavigationControllertitle에 표시된 URL의 제목이 설정됩니다
  • .

    이 쓰기의 좋은 곳


  • 없음

  • 이 쓰는 법의 나쁜 곳


  • "loading" , "estimatedProgress" 와 같이, 키를 베타 써야 한다
  • typo해도 컴파일 오류로 찾을 수 없음

  • deinit시 removeObserver
  • 그렇지 않으면 강제 종료 될 수 있음

  • 코드를 읽기 어려운

  • 그럼, 이것에 근거해 RxSwift를 사용한 패턴으로 구현



    RxWKWebViewController.swift
    import UIKit
    import WebKit
    import RxSwift
    import RxCocoa
    import RxOptional
    
    class RxWKWebViewController: UIViewController {
        @IBOutlet weak var webView: WKWebView!
        @IBOutlet weak var progressView: UIProgressView!
    
        private let disposeBag = DisposeBag()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupWebView()
        }
    
        private func setupWebView() {
    
            // プログレスバーの表示制御、ゲージ制御、アクティビティインジケータ表示制御で使うため、一旦オブザーバを定義
            let loadingObservable = webView.rx.observe(Bool.self, "loading")
                .filterNil()
                .share()
    
            // プログレスバーの表示・非表示
            loadingObservable
                .map { return !$0 }
                .observeOn(MainScheduler.instance)
                .bind(to: progressView.rx.isHidden)
                .disposed(by: disposeBag)
    
            // iPhoneの上部の時計のところのバーの(名称不明)アクティビティインジケータ表示制御
            loadingObservable
                .bind(to: UIApplication.shared.rx.isNetworkActivityIndicatorVisible)
                .disposed(by: disposeBag)
    
            // NavigationControllerのタイトル表示
            loadingObservable
                .map { [weak self] _ in return self?.webView.title }
                .observeOn(MainScheduler.instance)
                .bind(to: navigationItem.rx.title)
                .disposed(by: disposeBag)
    
            // プログレスバーのゲージ制御
            webView.rx.observe(Double.self, "estimatedProgress")
                .filterNil()
                .map { return Float($0) }
                .observeOn(MainScheduler.instance)
                .bind(to: progressView.rx.progress)
                .disposed(by: disposeBag)
    
    
            let url = URL(string: "https://www.google.com/")
            let urlRequest = URLRequest(url: url!)
            webView.load(urlRequest)
        }
    }
    
    
  • 사양은 정확히 동일

  • 좋은 곳


  • 읽기 쉬운
  • 간결한 처리
  • removeObserver 걱정하지 마세요

  • 나쁜 곳


  • 키 이름이 아직 쓰여져 있습니다
  • (조금 어긋나지만) 습득 비용이 높다

  • 요약


  • RxSwift를 사용하면 코드를 읽을 수 있고 구현이 간결해졌습니다
  • 귀찮아 removeObserver 걱정하지 않아도 좋아졌다
  • 높은 습득 비용

  • 소감


  • 따로 RxSwift를 사용하지 않아도 구현은 할 수 있다.
  • 하지만 인간은 잊어버립니다. 지금은 다이 작업에서도 removeObserver를 잊을 때가 절대 온다
  • 그 때 빠지지 않기 위해 RxSwift를 사용한 쓰기를 기억하고 싶습니다.
  • RxSwift에서 먼저 빠져 보인다.



  • 다음에 하고 싶은


  • RxWebKit라는 라이브러리가 있고 더 간결하게 걸릴 것 같았기 때문에 RxWebKit를 사용한 구현 샘플 기사를 쓴다
  • 좋은 웹페이지 즐겨찾기