ぴぽのたわごと

ジャンル問わず。自由気ままに書いてます。

【iOS】UIWebViewで読み込み終了時にJavaScript実行できなくてハマった。(swift3)

こんにちは。
swiftのお勉強を始めましたぴぽです。

僕がやりたかったことは、
Webページの読み込みが終わったらJavaScriptを実行させる
です。

なかなかハマりました。
なんとか解決法が分かったのでメモしておきます。

まず、僕の書いていたコードです。

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var webView: UIWebView!
    var js_func_String:String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Googleを開く
        let requestURL = NSURL(string: "https://www.google.com/")
        let req = NSURLRequest(url: requestURL! as URL)
        webView.loadRequest(req as URLRequest)
    }
    
    
    func webViewDidFinishLoad(webView: UIWebView) {
        // ページの読み込みが終わると呼ばれる

        webView.stringByEvaluatingJavaScript(from: "alert('Hello')")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

結論を言うと、
JavaScriptの実行文は間違っていませんでした。

webView.stringByEvaluatingJavaScript(from: "alert('Hello')")

これでJavaScriptは実行できます。

けど実行してもページは表示されるんですけど一向にアラートが出てこないんですよね。
読み込みが終わってもwebViewDidFinishLoadが呼ばれてなかったようです。

で、よくよく調べてみると
UIWebViewDelegateってのが必要なことがわかりました。

UIWebViewDelegateプロトコルは、UIWebViewオブジェクトのデリゲートが、ウェブコンテンツを読み込んだ時の実行を選択できるメソッドを定義します。
引用元 Second Flush

は?? デリゲート???
調べるた先でさらに分からないことが出てくると萎えますよね。

ザッと調べただけなんで曖昧ですけど、

他のクラスに処理を任せたり、通知を送るもの

って理解しました。(間違ってたらごめんなさい)

今回の例だと、「Webページの読み込み終わりましたよ」ってお知らせをどこに送るのかを指定していなかったので、終わったことに気づかなくてアラートも実行されなかったのかな。

それを踏まえて改良したコードがこちら!

import UIKit
class ViewController: UIViewController, UIWebViewDelegate {
    
    @IBOutlet weak var webView: UIWebView!
    var js_func_String:String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //  デリゲートの指定
        webView.delegate = self;
        
        // Googleを開く
        let requestURL = NSURL(string: "https://www.google.com/")
        let req = NSURLRequest(url: requestURL! as URL)
        webView.loadRequest(req as URLRequest)
    }
    
    func webViewDidFinishLoad(_ webView: UIWebView) {
        // ページの読み込みが終わると呼ばれる
        
        webView.stringByEvaluatingJavaScript(from: "alert('Hello')")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

変更点は3つです。

2行目:UIWebViewDelegate

class ViewController: UIViewController, UIWebViewDelegate

気づきにくいですよね、よく見たら参考にしていたサイトにも書いてました。
UIWebViewDelegateを継承するって感じかな(javaで言うextendsみたいな?)
これ書くことによってデリゲートの指定ができるようになります。

11行目:デリゲートの指定

webView.delegate = self;

= self で、お知らせはこのクラスにお願いします!って指定したことになるんですね。

19行目:引数にアンダースコア

func webViewDidFinishLoad(_ webView: UIWebView) {

上の2つの変更をするとXcodeの方から警告が出てきたので、言われるままに直しました。
よく分からないです。

とりあえず、これらの変更をして実行すると
f:id:pipoblog:20171208233331p:plain:w200

アラートしてくれました!!

たぶん本とか呼んで勉強してたらつまづくこともないんでしょうね。
精進します。