With my custom URLProtocol subclass, I made a custom URLResponse
subclass.
Oi vey! you really are trying to make life difficult for yourself here. I suspect that getting a custom NSURLResponse subclass all the way back from your custom NSURLProtocol subclass to the client app is going to be impossible. To understand why I think that, you have to understand a little about how all the bits fit together.
There are three layers in play here:
-
Swift (A)
-
Foundation (B)
-
CFNetwork (C)
For most Foundation URL loading system (FULS) classes there are equivalents at all three layers. In your example there is URLResponse
(A), NSURLResponse
(B), and CFURLResponse
(C), all of which are roughly equivalent. There are similarly named types for pretty much every FULS class (NSURLSession
, NSURLRequest
, NSCacheURLResponse
, NSURLCache
, and so on).
I’ve seen the A/B boundary cause problems for other types but I don’t think this is the issue here; URLResponse
is just a simple Swift renaming of NSURLResponse
and shouldn’t impact on custom subclasses.
The B/C boundary is much more exciting. First, some details about C:
-
CFURLResponse
is not actually a class, but rather a CF-style object.
-
The CF-style objects related to FULS are all private, but it’s important to understand them for two reasons:
-
They crop up all the time while debugging, especially when looking at crash logs.
-
The have a big impact on subclassing.
-
These CF-style objects exist because of a major architectural change back in the early days of Mac OS X, where the pure Objective-C FULS was rewritten to operate on top of CFNetwork, which exposes a CF-style API on top of a C++ core [1]. This means that a lot of things that should ‘obviously’ work, like subclassing NSCachedURLResponse
, don’t.
-
The documentation for FULS was originally written to the Objective-C implementation and thus you’ll still find references to subclassing in it.
Coming back to the big picture, my experience is that the B/C boundary causes a lot of grief when it comes to subclassing. Many Foundation classes (like NSURLRespones
) have an ‘is a’ relationship to an underlying CFNetwork type (CFURLResponse
), and that causes two problems:
-
The CFNetwork type might maintain state that you can’t see via the Foundation class. This is not uncommon, alas. For example, prior to the addition of -initWithURL:statusCode:HTTPVersion:headerFields:
in iOS 5 / OS X 10.7, it wasn’t possible to construct an NSHTTPURLResponse
using public API.
Note I’ve even seen this internal state issue show up on CFNetwork types. One example of this that’s still extant is the problem discussed on this thread (r. 6980095).
-
Subclassing the Foundation class won’t work if your object goes through the CFNetwork layer, and thus is converted to a CF-style object that does not maintain your subclass when it’s wrapped back into a Foundation class.
[1] So there’s actually a fourth layer here, layer D, consisting of C++ classes with names like URLResponse
(inside a C++ namespace, obviously). Again, knowing about these can be useful when looking at crash logs.
With regards your specific issue — returning a custom NSURLResponse
subclass from an NSURLProtocol
subclass — I suspect that this is impossible but I haven’t dug into it in depth and thus I’m not 100% sure. If you’d like me to take a proper look, please open a DTS tech support incident which will allow me to allocate the requisite time.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@" + "apple.com"