canGoBackとcanGoForwardを監視する

はじめに

WKWebViewをカスタマイズしてアプリを作成していく際に欠かせないのがcanGoBackcanGoForwardですが、用件が複雑化していくとうまく取得できなくなってしまう時があります。

そんな時はKVOを使って監視することでイベント通知を受け取ることが可能になります。

canGoBackってそもそもKVO使えるの?

最初、Hogeクラスのcountを下記のように定義していました。

これではKVOはうまく動きませんでした。

var count: Int = 0

下記のようにobjc dynamicを指定すると正常に動作します。

@objc dynamic var count: Int = 0

監視対象の変数にはdynamicの指定が必要なようです。

Swift4からobjcの指定が必要になったようです。

https://qiita.com/y_kuru/items/9ad9c9a17ff5822f9496

Qiitaからの引用でわかるように本来KVOを使う時には監視対象の変数に @objc dynamicをつける必要があります。

しかしjump to DefinisionでWKWebViewの定義元に飛ぶと以下のようにプロパティが定義されていました。

open var canGoBack: Bool { get }
open var canGoForward: Bool { get }

@objc dynamicはついていのですが、概要を読むとKVOに準拠してある!と記載されていたので使えるようです。

おそらくAppleが開発者には見えないところで良い感じにやってくれているのだと思います。

/** @abstract A Boolean value indicating whether there is a forward item in
the back-forward list that can be navigated to.
@discussion @link WKWebView @/link is key-value observing (KVO) compliant
for this property.
@seealso backForwardList.
 */

KVOを使ったプロパティの監視

以下がcanGoForwardとcanGoBackを監視した際のコードです。

監視する際のおおよその使い道は進むボタンと戻るボタンの活性非活性の判定に使うと思うのでその処理も入れておきました。

[iOS 8] WKBackForwardList で 閲覧履歴を管理する少し古い記事ですが、Objc時代にも同じことをやりたいとおもった方がいたようで同じようにKVOで監視して判定を行っているようでした。

private var observers = [NSKeyValueObservation]()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //canGoForwardの監視
        observers.append(webView!.observe(\.canGoForward, options: .new) { [weak self] (_, _) in
            if self?.webView?.canGoForward ?? false {
                //canGoForwardできる時の処理
            } else {
                //canGoForwardできない時の処理
            }
        })

        //canGoBackの監視
        observers.append(webView!.observe(\.canGoBack, options: .new) { [weak self] (_, _) in
            if self?.webView?.canGoBack ?? false {
                //canGoBackできる時の処理
            } else {
                //canGoBackできない時の処理
            }
        })
    }
    
    deinit {
        observers.removeAll()
    }

参考文献

SwiftでKVO(Key-Value Observing)

[iOS 8] WKBackForwardList で 閲覧履歴を管理する