Есть ли ошибка с использованием InnerHTML внутри UIWebView в родном приложении iPhone?

У меня довольно большое приложение HTML/JS/CSS, которое отлично работает при работе в качестве веб-приложения с Safari на iPhone.

При запуске этого же приложения в UIWebView внутри собственного приложения iPhone вызовы в jQuery для создания фрагментов HTML сбой молча (т.е. $("<div>HELLO WORLD</div>"); не будет создавать элемент.

Я проследил это до следующего эквивалентного фрагмента кода в чистом методе jQuery:

var div = document.createElement("div"); div.innerHTML = "<div>HELLO WORLD</div>";

Когда я смотрю div.outerHTML, я вижу <div>/<div>

div.innerHTML возвращает пустую строку.

Это не проблема jQuery, и это не происходит в 100% случаев. Мне не удалось найти шаблон, но в некоторых случаях он работает 2-3 раза подряд, иногда, если не удается выполнить 5-6 раз подряд. Кажется, это проявляется только при запуске приложения внутри UIWebView в приложении Objective-C. Также Ive видел это только на реальном устройстве под управлением iOS 4.2, а не на эмуляторе.

Кто-нибудь сталкивался с чем-то похожим? У кого-нибудь есть проблема?

Ответ 1

У меня тоже были проблемы. Это происходит, когда процессор телефона очень занят (скажем, 100%). Затем механизм рендеринга иногда забывает о настройках innerHTML.

Решение, включенное в мой унифицировать проект, - проверить, есть ли элемент в childNodes, иначе примените его снова.

var target = document.createElement("div");
var text = "<div>Hello World</div>";
target.innerHTML = text;
var self = this;
self.__intervalHandle = window.setInterval(function() {
  target.innerHTML = text:
  if (target.firstChild) {
    window.clearInterval(self.__intervalHandle);
    self.__intervalHandle = null;
  }
}, 100);

Это заставляет механизм рендеринга применять innerHTML к DOM и дает механизм рендеринга некоторое время (100 мс в этом примере, хорошее значение в наших тестах) для его обработки.

Ответ 2

Ну, решение [НЕ решение качества продукции], опубликованное Sebastian, работало, но я не мог подтвердить, может ли загрузка процессора вызвать эту проблему. Я создал много фоновой нагрузки на хост iOS и не смог воспроизвести эту проблему.

При дальнейшем исследовании проблема рендеринга, по-видимому, является побочным эффектом оболочки iOS, отменяющей навигацию. После того, как навигация отменена оболочкой iOS, механизм рендеринга, вероятно, считает, что не нужно отображать больше пользовательского интерфейса (в основном ничего не делает за небольшой период).

Один из способов исправить это - отправить команды в оболочку iOS как параметры хэша (#) вместо URL. Таким образом, оболочка iOS получит команды и не нуждается в отмене навигации. Этот подход, похоже, работает в тестовом коде ниже. Итак, если window.location установлен в location1, он предупреждает "At: 1", а элемент e2 не имеет значения. И если для окна .location установлено значение location2, он предупреждает "At: 0", а элемент e2 имеет значение.

@Kevin, не могли бы вы подтвердить, что вы отменяли навигацию на хосте iOS, когда это происходило.

Тестовый код:

JavaScript:

    var location1 = "myApp://Test";
    var location2 = "#myApp://Test";
    $("#change").live("click", function (e) {
        var element = document.getElementById("e1");
        window.location = location1; var i = 0;            
        element.innerHTML = "At: " + i;
        window.__intervalHandle = window.setInterval(function () {
            var html = element.innerHTML;
            if (html) {
                 alert(html);
                window.clearInterval(window.__intervalHandle);
                window.__intervalHandle = null;
            } else {
                element.innerHTML = "At: " + ++i;
            }
        }, 1);
        document.getElementById("e2").innerHTML = "Test";
    });

псевдо-код iOS:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL* u = [ request URL];

if( [[u scheme] compare:@"myapp" ] == NSOrderedSame) {
{ 
return NO; // don’t navigate
}
return YES; // navigate
}

Ответ 3

Вы должны взглянуть на http://blog.techno-barje.fr/post/2010/10/06/UIWebView-secrets-part3-How-to-properly-call-ObjectiveC-from-Javascript.

Оказывается, что отмена навигации как части метода делегата -webView:shouldStartLoadWithRequest: может вызвать проблемы с innerHTML. Я обновил наш JS-код, чтобы использовать метод, рекомендованный в этой статье, и я не видел, как проблема с innerHTML возникла через некоторое время.