UIWebViewDelegate: webViewDidFinishLoad не вызывается во время навигации по странице

У меня есть приложение, в котором пользователи могут перемещаться по куче локально сохраненных файлов HTML. У меня есть UIWebView, правильно настроенный с UIWebViewDelegate. Обычно, когда пользователь переходит по ссылке, вызывается shouldStartLoadWithRequest, а чуть позже webViewDidFinishLoad.

Но если ссылка указывает на якорь на той же странице, что и отображаемая в данный момент, вызывается только shouldStartLoadWithRequest. webViewDidFinishLoad не срабатывает.

В каком-то смысле я вижу, что это ожидаемое поведение, потому что внутристраничная навигация не должна требовать перезагрузки страницы. Однако мне действительно нужно место для подключения к стеку вызовов после завершения навигации по странице. Оптимальное решение дало бы мне знать, когда закончилась какая-либо навигация, как с другой страницы, так и внутри страницы, а также действия вперед/назад.

Мой лучший обходной путь до сих пор состоял в том, чтобы вызвать performSelector: withObject: afterDelay: в конце моего метода shouldStartLoadWithRequest, но я не доволен этим.

Кто-нибудь знает, как я могу решить это правильно? Любое понимание ценится!


person thomax    schedule 27.03.2013    source источник
comment
Я не вижу вызов shouldStartLoadWithRequest для любого щелчка привязки, загружается только полная страница. Мне любопытно, изменилось ли это поведение, или, если нет, я должен делать что-то не так.   -  person Jason    schedule 24.06.2014


Ответы (6)


Можно попробовать использовать NSURLConnectionDataDelegate, он позволяет обрабатывать входящие данные. Возможно, вы можете определить, загружается ли страница вручную, добавив знак в ваши html-файлы.

Справочник NSURLConnectionDataDelegate

Изменить: gist.github.com/buranmert/7304047 Я написал фрагмент кода, и он сработал. , это может быть не так, как вы хотели, но, возможно, это поможет. Каждый раз, когда пользователь щелкает URL-адрес с якорем, он создает другое соединение, и когда соединение завершает загрузку веб-представления, загружаются данные, которые отмечают точку, в которой веб-представление завершило загрузку страницы. Поскольку вы используете только локальные файлы html, я не думаю, что создание соединений создаст проблемы.

person Mert Buran    schedule 04.11.2013
comment
Спасибо за ответ! Единственный метод на NSURLConnectionDataDelegate, который, кажется, имеет какой-либо потенциал в моем случае, это connectionDidFinishLoading. При чтении описания метода это звучит не слишком многообещающе, так как сомнительно, что внутристраничная навигация вызовет загрузку. Но я попробую. - person thomax; 04.11.2013
comment
Ура! У меня это работает! На мой взгляд, лучшее решение, предложенное здесь. Большое спасибо, что нашли время, чтобы помочь мне. Награда твоя, добрый сэр! - person thomax; 11.11.2013
comment
На самом деле обратный вызов/перехватчик на webView.renderingFinished был бы идеальным на 100%, но и этого достаточно. - person thomax; 11.11.2013
comment
Да, я сначала подумал, это будет решением, это скорее обходной путь. Я рад, что это помогло тебе, приятель - person Mert Buran; 11.11.2013
comment
Еще одна интересная особенность этого решения заключается в том, что UIWebViewNavigationTypeBackForward покажет, использовались ли кнопки «назад/вперед». - person thomax; 11.11.2013
comment
@MertBuran См. stackoverflow.com/ вопросов/30380848/ -- может быть, простой вопрос для вас. - person Paul Cezanne; 21.05.2015

То, что вы описываете, является предполагаемым поведением. Точно так же, как AJAX или запросы ресурсов никогда не передаются делегату, только изменения корневой страницы когда-либо попадут в webViewDidFinishLoad:. Но у меня есть хорошие новости, и это не связано с экономией денег на страховке автомобиля.

Загрузки, выполняемые внутри iFrame DO, запускают полные методы делегата, и это дает вам решение. Вы можете использовать этот механизм для отправки уведомления в собственный код, как это часто делается для console.log(), как описано в этом сообщении. В качестве альтернативы, Native Bridge хорошо подойдет для вызова вашего кода Objective C из JavaScript.

person Holly    schedule 07.11.2013
comment
+1 Я уверен, что это сработает, но это больше похоже на взлом, чем на более похожее на iOS предложение Мерта Бурана. Однако большое спасибо за помощь! - person thomax; 11.11.2013

Просто проверьте, есть ли у вас функция делегата DidStartLoading, если она вызывается, без сомнения, DidFinish также должна быть вызвана.

person Nagaraj    schedule 11.11.2013
comment
Нет, он не вызывается при навигации по странице с фрагментом URL-адреса. - person thomax; 11.11.2013
comment
Проверьте, что погода webView:shouldStartLoadWithRequest:navigationType: возвращает NO, и еще одна возможность: для делегата веб-просмотра установлено значение nil - person Nagaraj; 12.11.2013
comment
shouldStartLoadWithRequestвозвращает YES, и делегат установлен правильно. Это, собственно, и есть предпосылка моего вопроса. - person thomax; 12.11.2013
comment
Вызов функции проверки погоды приходит к делегату shouldStartLoadWithRequest, и веб-просмотр погоды загружает страницу. Если все в порядке, тогда, если возможно, опубликуйте фрагмент ht ecode, чтобы я мог проверить. - person Nagaraj; 13.11.2013

Вы уверены, что ваш shouldStartLoadWithRequest всегда возвращает YES???

я всегда добавляю

return YES;

в конце реализации shouldStartLoadWithRequest. И это работает для меня. Возвращая YES, это означает, что веб-представление загрузилось и вызовет webViewDidFinishLoad.

person Shob-Z    schedule 05.11.2013

Вот быстрая реализация кода Мерта Бурана, если кто-то его ищет. (Хотя NSURLConnection устарел с iOS 9)

Но это не решает мою проблему. Когда я нажимаю на ссылку jquery, которая открывает видео, он не запускает webViewDidFinishLoad.

class WebViewController: UIViewController, UIWebViewDelegate, NSURLConnectionDelegate {

var menuURL: String?

var response: NSURLResponse?
var data = NSData()

// MARK: Properties
@IBOutlet weak var webView: UIWebView!

override func viewDidLoad() {
    super.viewDidLoad()

    webView.delegate = self

    // From Web
    let url = NSURL (string: menuURL!)
    let urlRequest = NSURLRequest(URL: url!)

    let connection = NSURLConnection(request: urlRequest, delegate: self)
    self.data = NSData()
    connection!.start()

    // if this is false, page will be 'zoomed in' to normal size
    webView.scalesPageToFit = false

}

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    if navigationType == .LinkClicked && request.URL!.fragment != nil {
        let connection = NSURLConnection(request: request, delegate: self)
        connection!.start()
        return false
    }
    return true
}

func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
    self.response = response
}

func connection(connection: NSURLConnection, didReceiveData data: NSData) {
    let oldData = NSMutableData(data: self.data)
    oldData.appendData(data)
    self.data = oldData
}

func connectionDidFinishLoading(connection: NSURLConnection) {
    self.webView.loadData(self.data, MIMEType: self.response!.MIMEType!, textEncodingName: "utf-8", baseURL: self.response!.URL!)
    self.data = NSData()
}


}
person Gaga    schedule 24.08.2016

person    schedule
comment
Да, но опрос webView для его состояния загрузки не является обратным вызовом / ловушкой ОС, а наоборот. - person thomax; 11.11.2013