7

Short version: in my app background fetch works like a charm except that when I try to load contents in a webview it does nothing at all!

Long version: I set the right capabilities in the project, set the fetch interval and implement the

- (void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

method as in the examples and it works. But then, to complete my background fetch I need to load some contents in a UIWebView. And this doesn't work. Simply the process somehow "get lost" when i call:

[myWebview loadRequest:request];

(of course it works when in foreground, but does nothing when in background).

I also try to force the webview to be loaded in the main thread, but then the system simply halt it 'till the app return in foreground mode (it make sense, we are in background!)

So, there's a way to load a UIWebView while in background? Please note I can't simply download the contents with NSURLSession, 'cause the webpage contains javascript that load some of the frames (and I can't ask for a redesign of the webpage).

Edit: probably I wasn't crear enough when I wrote the question, but trying to execute a task it in the main_queue (with a dispatch_async o likewise methods) while in a background fetch does not work. I tried it before asking...

2 Answers2

3

When you want to update elements from the user interface, you have to access them in the main queue (or thread) of the application. What I would recommend is for you to keep getting the data you need in the background, but when it is time to update your UIWebView, do it in the main thread. You can do it like this:

    dispatch_async(dispatch_get_main_queue(), ^{

        // Load fetched data in the Web View

    });   

or you could create a method that updates the data on the UIWebView and call it from the background thread using:

[self performSelectorOnMainThread:@selector(method:) withObject:fetchedData waitUntilDone:YES];

This will ensure that you access the UIWebView from the correct thread.

Hope this helps.

Eduardo Arenas Prada
  • 1,072
  • 1
  • 7
  • 14
  • No it doesn't work! I already try it, but as I wrote if I do the web view load in the main queue the block execution simply halt till the app return to foreground (then it start immediately, but of course is too late...) – il Malvagio Dottor Prosciutto Oct 31 '13 at 08:00
  • What I meant is that you need to separate your code in two parts. One fetches the data from the server (I believe you are expecting to receive some html and javascript) and the other loads the fetched data into the `UIWebView`. The first part should be called from a background thread so it doesn't block the user interface, and once you get the data you should update the `UIWebView` in the main thread, to ensure the view does get updated. Taking this into account, using `[myWebview loadRequest:request];`probably won't work for you, and you should find another way to update your web view. – Eduardo Arenas Prada Oct 31 '13 at 12:55
  • I can't separate sadly... The javascript that i download trigger some more downloads, so I need the web view to execute them.. – il Malvagio Dottor Prosciutto Nov 01 '13 at 20:02
  • I believe you could use `loadData:MIMEType:textEncodingName:baseURL:`, but honestly I'm not sure if this will run the Javascript the way you need it. If it does, it might solve your problem. – Eduardo Arenas Prada Nov 01 '13 at 20:20
  • 1
    if you're trying to execute code on multiple threads using GCD like you are here, you have to be careful to use dispatch_async rather than dispatch_sync, it is easy to mistakenly cause a deadlock with threads which would cause the app to appear like it has stuck like you describe. Obviously, not every situation calls for dispatch_async, but this situation seems that is the source of the problem. – JConway Nov 10 '13 at 12:21
  • Again, no! Using dispatch_async(dispatch_get_main_queue().... in a background fetch **DOES NOT WORK!** please read my comments before repeating the same stuff: when you are in a background fetch if you call for the main queue it waits till the app goes foreground to start the block! – il Malvagio Dottor Prosciutto Nov 12 '13 at 08:22
2

At 11/11/2013 (iOS 7.0.3) looks like is not possible. I just leave this answer so people will not get wrong info.

The solution of Eduardo Arenas Prada works perfectly if your application is in foreground, but not in a background fetch sadly.