Индикатор выполнения (и состояние сетевой активности) для UIWebView

После долгого перерыва яМы снова начали заниматься ios development. Имея это в виду, я скачал последнюю версию XCode (5.02) и принялся кодировать приложение с ios7 в качестве цели. Все шло хорошо, пока я не добавил "веб-страница просмотра " к моему приложению. Я наивно ожидал, что UIWebView будет работать как страница в Safari, но это не так.т. Самое очевидное, чего не хватает, это то, чтоНет абсолютно никакой обратной связи с пользователем, пока страница загружается. то есть индикатор активности сети нене появляется вообще и тампри загрузке страницы не отображается индикатор выполнения. Так что я решил, что вы просто должны добавить их вручную. Это не должноне должно быть слишком сложно, не так ли?

Несколько дней спустя и яу меня это работает довольно хорошо, но ям не на 100% доволен результатом. Потребовалось немало отладок и экспериментов, чтобы добраться до того места, где я сейчас нахожусь. Я думаю, мой вопросЧто-нибудь можно сделать, чтобы улучшить мой подход? " а также, возможно, "Должен ли я сообщить Apple о проблемах с загрузкой и запросить свойства и попросить их исправить их?

Первоначально я искал в Интернете решения этой проблемы, и по стеку стекалось немало вопросов, но, похоже, никто его не взломал. Некоторые из предложенных подходов:

Используйте частный API UIWebView (бесполезно, если вы хотите выпустить свое приложение в магазин)Загрузите страницу, используя NSURLConnection (дает прогресс только для начальной загрузки страницы)Используйте стороннюю библиотеку для загрузки и обработки страницы (кувалдой сломать орех?)Используйте UIWebViewDelegate и отслеживайте начало и конец загрузкиИспользуйте UIWebViewDelegate, чтобы вручную показать и скрыть индикатор сетевой активности.

В конце концов я решил использовать 4. и 5. но этосложно, потому что:

Начальный и конечный вызовы могут поступать в любом порядкеНекоторые запросы начинаются, но никогда не заканчиваютсяНекоторые запросы завершаются с ошибкой

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

Вторая проблема труднее решить. UIWebView имеет два свойства, которые в принципе можно использовать для этого (загрузка и запрос), но они, похоже, работают таинственным образом. В некоторых ответах и комментариях, которые я нашел здесь, предполагается, что свойство загрузки никогда не обновляется, но запрашивается одно. Это изначально имело смысл для меня, потому что страницы никогда не перестают загружаться (они могут иметь динамическое содержимое), поэтому имело смысл, что свойство загрузки сообщит вам только, если веб-представление активно загружает содержимое (т. Е. Был ли вызван loadRequest и нет stopLoading). 'т).

Тем не менее, по крайней мере, на ios7 он работает наоборот. Свойство запроса никогда не обновляется, поэтому вы можетеt использовать свойство запроса, чтобы определить, завершил ли представление загрузку всего (то есть, проверив, является ли завершенный запрос начальным запросом). Свойство loading обновляется, и оно становится равным NO, когда страница полностью загружена. Это очень помогает, но яМы заметили, что динамический контент (например, реклама на страницах) приводит к тому, что загрузка возвращается к YES, поэтомус этим все еще немного сложно иметь дело.

Третья проблема нене проблема, кроме менямы заметили, что внутри webView: didFailLoadWithError свойство загрузки всегда имеет значение NO. Однако это временное состояние, и если вы хотите, вы можете игнорировать ошибки и подождать, пока загрузке будет присвоено значение NO в webViewDidFinishLoad. Так как свойство запроса не являетсят обновил этоневозможно знать, если этоs первоначальный запрос, который не прошел, или один из подзапросов (которые могут вас интересовать, а могут и не заботиться). Так что я'Мы решили использовать решение, позволяющее программисту выбирать желаемое поведение.

Все будет проще, если:

свойство запроса было обновлено (или был передан текущий запрос, как в webView: shouldStartLoadWithRequest: navigationType)свойство загрузки было правильно установлено в webView: didFailLoadWithError

Вот'Мой код внутри контроллера представления для webView:

- (void)resetProgress {
    framesToLoad = 0;
    framesLoaded = 0;
    currentProgress = 0.0f;
}

- (void)resetForNewPage {
    // Reset progress
    [self resetProgress];

    // Monitor the page load
    monitorProgress = YES;

    // Keep going if errors occur
    // completeIfError = NO;

    // Stop updates if an error occurs
    completeIfError = YES;
}

- (void)webViewLoaded {
    [self resetProgress];
    [entryProgressView setProgress: 0.0f animated: YES];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // Reset state for new page load
    [self resetForNewPage];

    // Load the page
    NSURLRequest *entryRequest = [NSURLRequest requestWithURL:entryURL];
    [entryWebView loadRequest:entryRequest];
}

-(void)viewWillDisappear:(BOOL)animated {
    [entryWebView stopLoading];

    entryWebView.delegate = nil;
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        // Reset state for new page load
        [self resetForNewPage];
    }

    return YES;
}

-(void)webViewDidStartLoad:(UIWebView *)webView {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    if (!monitorProgress) {
        return;
    }

    // Increment frames to load counter
    framesToLoad++;
}

-(void)webViewDidFinishLoad:(UIWebView *) webView {
    if (!monitorProgress) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        return;
    }

    // Increment frames loaded counter
    framesLoaded++;

    // Update progress display
    float newProgress = ((float) framesLoaded) / framesToLoad;
    if (newProgress > currentProgress) {
        currentProgress = newProgress;
        [entryProgressView setProgress: newProgress animated: YES];
    }

    // Finish progress updates if loading is complete
    if (!webView.loading) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        monitorProgress = NO;

        [entryProgressView setProgress: 1.0 animated: YES];
        [self performSelector:@selector(webViewLoaded) withObject: nil afterDelay: 1.0];
    }
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    if (!monitorProgress) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        return;
    }

    // Increment frames loaded counter
    framesLoaded++;

    // Update progress display
    float newProgress = ((float) framesLoaded) / framesToLoad;
    if (newProgress > currentProgress) {
        currentProgress = newProgress;
        [entryProgressView setProgress: newProgress animated: YES];
    }

    // Finish progress updates if required
    if (completeIfError) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        monitorProgress = NO;

        [entryProgressView setProgress: 1.0 animated: YES];
        [self performSelector:@selector(webViewLoaded) withObject: nil afterDelay: 1.0];
    }
}

Ответы на вопрос(0)

Ваш ответ на вопрос