A NSURLSessionTask Debug Story

While working on AsyncDisplayKit, we ran into a strange iOS compatibility bug. Our Kittens example project was working just fine for iOS 8, but when we ran the project on iOS 7 it instacrashed.

There was an unrecognized selector being sent to a NSURLSessionTask object. We were using the Objective-C runtime headers to slap on a metadata object for some convenience properties:

@implementation NSURLSessionTask (ASBasicImageDownloader)
static const char *kMetadataKey = NSStringFromClass(ASBasicImageDownloaderMetadata.class).UTF8String;
- (void)setAsyncdisplaykit_metadata:(ASBasicImageDownloaderMetadata *)asyncdisplaykit_metadata
{
  objc_setAssociatedObject(self, kMetadataKey, asyncdisplaykit_metadata, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (ASBasicImageDownloader *)asyncdisplaykit_metadata
{
  return objc_getAssociatedObject(self, kMetadataKey);
}
@end

Nothing special.

In order to debug the crash, I placed a breakpoint just before the setter that was crashing. I fired up the app on my iPhone 4 running iOS 7.1 and waited for the breakpoint to hit.

As soon as the Debugger window popped up, I used our chisel lldb extensions to inspect the class hierarchy of the object with pclass:

__NSCFLocalDownloadTask
   | __NSCFLocalSessionTask
   |    | __NSCFURLSessionTask
   |    |    | NSObject

That's odd. We are creating a NSURLSessionTask object. That class doesn't even show up in the dump.

Just to be safe, I printed the class hierarchy of the same object when running on iOS 8.1:

__NSCFLocalDownloadTask
   | __NSCFLocalSessionTask
   |    | NSURLSessionTask
   |    |    | NSObject

It appears that the NSURLSessionTask factory method downloadTaskWithURL: has some black-box magic happening on iOS 7.

Since __NSCFLocalDownloadTask doesn't inherit from NSURLSessionTask on iOS 7, that means that our associated object wont exist on our task object.

All we had to do was change the class to NSURLSessionDownloadTask and everything worked just fine. My hunch is that NSURLSessionTask is some sort of class-cluster similar to UIButton.