0

I am using MoPub for ad mediation in my iOS app. I received a couple of user complaints about blocked UI when an ad is loading. I could replicate this only under certain low-quality network conditions.

My naive assumption was that all I had to do was call the MPAdView.loadAd from a background thread via dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{, and update the UI with dispatch_async(dispatch_get_main_queue() in the adViewDidLoadAd delegate method (that gets called when an ad has been loaded by the MoPubSDK).

But as it turns out, this did not work - the delegate method is never called.

I traced the problem back into the MoPubSDK, where a NSURLConnection is initialized via:

self.connection = [NSURLConnection connectionWithRequest:[self adRequestForURL:URL] delegate:self];

but the NSURLConnectionDelegate methods (like connectionDidFinishLoading) themselves are never called when executed on the background thread. It works when the call is made on the main thread.

I noticed that the "current mode" of [NSRunLoop currentRunLoop] is "(none)" when executed on the background thread, but "kCFRunLoopDefaultMode" when executed on the main thread.

The NSURLConnection docs mention

For the connection to work correctly, the calling thread’s run loop must be operating in the default run loop mode.

so I tried setting it explicitly using

 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[[NSDate alloc] initWithTimeIntervalSinceNow:60]];

but this had no effect.

So, what do I need to do to ensure that the NSURLConnection delegate methods get called when the connection is initialized in a background thread?

thomers
  • 2,603
  • 4
  • 29
  • 50

2 Answers2

0

Ok, after hours of searching, I wrote that question - and of course, 15 mins later, I find one possible solution on SO...

self.connection = [[NSURLConnection alloc] initWithRequest:[self adRequestForURL:URL] delegate:self startImmediately:NO];

NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[self.connection scheduleInRunLoop:runLoop forMode:NSRunLoopCommonModes];
[self.connection start];
[runLoop run];

This ensures that the NSURLConnection delegate methods are called.

(I now have a different problem "This may be a result of calling to UIKit from a secondary thread." - but this is unrelated to the original question).

Community
  • 1
  • 1
thomers
  • 2,603
  • 4
  • 29
  • 50
0

You should probably be scheduling the connection object on the main run loop instead of the current one. That will not only avoid the issue of scheduling it on a nonfunctional run loop (what the heck?), but also will ensure that when a request finishes, the ad framework won't try to do UI operations on the wrong thread.

dgatwood
  • 10,129
  • 1
  • 28
  • 49