0

I have configured a URLSession to fetch data from network & have set a delegate queue so that all subsequent operations happen within my queue. However, when using breakpoints to view the Debug navigator, Xcode shows the completion block of URLSession is invoked on arbitrary threads.

The URLSession is setup as follows -

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

self.urlSession = [NSURLSession sessionWithConfiguration:configuration delegate:nil delegateQueue:[MyManager sharedInstance].queue];

...

[self.urlSession dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

  /... operations expected to be executed on WEGQueue .../

}] resume];

Below is screen capture of processes on my serial queue named WEGQueue before URLSession has started.

Pic 1

Now I expect the completion block operations to be invoked on the specified delegate queue of URLSession i.e. WEGQueue here. However, using a breakpoint to view the Debug Navigator shows that block is being processed on an arbitrary queue. Attached pic below.

Pic 2

Below is Debug Navigator in "View Process by Queue" filter.

enter image description here

This is really weird! I'm not sure why URLSession is not invoking completion blocks on the specified delegate queue. And that's not all. It gets weirder due to the fact that when I do a po, lldb says that the completion block is (as expected) on the WEGQueue. See pic below.

Pic 3

It's confusing that Xcode's Debug Navigator says URLSession's completion block is being executed on an arbitrary thread while lldb says it is executed as expected on the delegate queue WEGQueue.

Did anyone face a similar scenario? Is this just an Xcode GUI bug? Or something is really amiss over here?

ystack
  • 1,785
  • 12
  • 23
  • 1
    I thought that you couldn't mess using Completion Blocks and Delegate with `URLSession`, it was either one or the other. Cf. https://stackoverflow.com/a/37902228/1801544 and doc https://developer.apple.com/documentation/foundation/nsurlsessiondatadelegate#/apple_ref/occ/intf/NSURLSessionDataDelegate – Larme Jan 14 '19 at 14:07
  • @Larme I have not implemented any `NSURLSessionDataDelegate` delegate funcs. I'm using the Completion Blocks implementation but want the block to be executed on my own `NSOperationQueue` i.e. WEGQueue here. I want all completion block operations executing on this custom queue instead of URLSession arbitrarily creating one to execute it. – ystack Jan 14 '19 at 14:14
  • Since it's called `delegateQueue:`, I think that's why. It's for the delegate and might not care if you use the block. If it was called `queue:`, it wouldn't have surprised me that it worked, but since it's not, that's the init special for delegate case. – Larme Jan 14 '19 at 14:15
  • I thought about that naming pattern but couldn't find any documentation claiming this to be the case. Also, the official docs say `An operation queue for scheduling the delegate calls and completion handlers.`https://developer.apple.com/documentation/foundation/nsurlsession/1411597-sessionwithconfiguration?language=objc – ystack Jan 14 '19 at 14:19
  • If you change your display to "View Process by Queue" does it say your completion routine is in an unexpected queue? (Perhaps it's just a problem with the "by Thread" view.) – Phillip Mills Jan 14 '19 at 15:08
  • Thanks for the heads-up @PhillipMills but however it's inconclusive to me. See the attached pic. Xcode still states that block was enqueued from an arbitrary thread. – ystack Jan 14 '19 at 15:24
  • I thought the delegate queue controls only where the delegate callbacks run. But the docs do say this about the delegate queue: "An operation queue for scheduling the delegate calls **and completion handlers**". So...hmmm... doc error? The surprise about the thread isn't surprising. The app doesn't control which thread a queue's task uses. You can sidestep the queue mystery by explicitly dispatching in your completion handlers. – danh Jan 14 '19 at 16:21
  • In your first screen shot, the "WEG Queue" is marked as "concurrent". That would explain the behaviour, because then there can be multiple threads handling the same queue. Are you sure that it is a Serial Queue, and not a concurrent one? Technically, even if it is a serial queue, it could be handled by multiple threads, as long as the handling of the operations don't overlap. – fishinear Jan 14 '19 at 20:21
  • I think it is just a glitch in the XCode UI, that is has not marked the threads with the name of your queue. – fishinear Jan 14 '19 at 20:26
  • @fishinear Yes, WEGQueue is a Serial queue. I've set the queue's max concurrent operations limit to 1 while initialising it. – ystack Jan 15 '19 at 09:14

1 Answers1

0

I'd say it is just an XCode GUI limitation, that it does not always label the Queue in the "view by queue" with the name that you gave it. And it does not always label the threads with the Queue that thread is currently handling. As you say, when you do po [NSOperationQueue currentQueue], it does report the correct queue. So you have no indication that it actually uses another queue.

There is no guarantee that the same queue is always handled by the same thread. Each event can be handled by a different thread. There is only a guarantee that the events are not running in parallel, for a Serial Queue.

fishinear
  • 6,101
  • 3
  • 36
  • 84