Subclassing factory methods of URLSession in Swift
Asked Answered
A

1

5

I am trying to create a subclass of URLSession in Swift (reason does not matter, but has to do with testing). I need it to work with a delegate and a specific URLSessionConfiguration, which is a read-only property on URLSession. Usual way to initialize URLSession with delegate is done with the code below, which works flawlessly:

let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil)

Now lets create a subclass:

class MyURLSession : URLSession {}

let session = MyURLSession(configuration: 
URLSessionConfiguration.default, delegate: nil, delegateQueue: nil) // Compile error

The initializer triggers next compile error:

error: argument passed to call that takes no arguments

According to Swift Language Guide rule 1 for Automatic Initializer Inheritance:

If your subclass doesn’t define any designated initializers, it 
automatically inherits all of its superclass designated initializers.

So, technically MyURLSession should inherit all designated initializers, but it doesn't, and it only inherits init() from NSObject. Looking into documentation of URLSession:

public /*not inherited*/ init(configuration: URLSessionConfiguration)
public /*not inherited*/ init(configuration: URLSessionConfiguration, delegate: URLSessionDelegate?, delegateQueue queue: OperationQueue?)

There is nothing visible aside from the comment, that it is not inherited. Looking into it's Objective-C definitions, we can notice that they are not initializers, but rather factory methods, which are imported into Swift as inits.

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

So the question is, how to override and/or correctly call these methods of superclass in initialization?

Apprehensive answered 8/1, 2018 at 21:42 Comment(0)
I
6

You should not be subclassing URLSession. You don't get access to the initialiser methods you are wanting to access and the URLSessionConfiguration and delegate properties are read only so you will have no way to set them.

Basically there is no way to do what you want with subclassing.

If you are concerned with testing URLSessions then perhaps take a look at something like this Mock Objects For Testing

Inquietude answered 8/1, 2018 at 22:0 Comment(6)
Thank you for your answer. Yes, you are correct on the not subclassing URLSession and I am aware how to test using mocks. This question remains, if it is generic: on how to override compiler generated initializers from factory methods, URLSession was merely an example.Apprehensive
I see you mean in a more generic sense. Well for a start while they may be factory methods in ObjectiveC there are initialisers in Swift which you can tell by there definition. Also those functions are not 'imported' into Swift form ObjectiveC they are fully defined within Swift itself. The URLSession in Swift and NSURLSession in ObjectiveC are two different things there is just an automatic bridge (conversion) between the two.Inquietude
All correct, but doesn't explain how can I call them from a subclass. :) More and more research I do, more it looks like it just isn't possible.Apprehensive
That's what I said in my answer. There is no way to do what you want to do with subclassing because URLSession is not designed to be subclassed. If you do you can't access those initialisers for the subclass and you won't be able to set the session configuration or delegate for the subclass either because they are read only. If it's for testing purposes then go the Mock Objects route otherwise instead of subclassing you need to create a wrapper for URLSession or an extension.Inquietude
I do believe subclassing in Objective-C could work. I just wanted to understand what happened under the hood that this initializer is not available in subclass.Apprehensive
Possibly with ObjectiveC as I haven't looked into it. If I get time I will have a look later.Inquietude

© 2022 - 2024 — McMap. All rights reserved.