Cannot invoke 'dataTask' with an argument list of type...

I have this vanilla piece of code I virtually use everywhere in my code:

let configuration = URLSessionConfiguration.default
let session = URLSession(configuration:configuration)
let listTask = session.dataTask(with: theRequest, completionHandler:{[weak self](data, response, error) in
})

Yet in one particular class the compiler reports:

Cannot invoke 'dataTask' with an argument list of type '(with: URLRequest, completionHandler: (Data?, URLResponse?, Error?) -> ())' Expected an argument list of type '(with: URLRequest, completionHandler: (Data?, URLResponse?, Error?) -> Void)'

How does it infer the return value of the closure to be () instead of Void?

I copied the code from other classes repeatedly lest I wrote something wrongly.

Accepted Reply

Try:


(a) putting a 'return ()' in the closure, or


(b) removing the [weak self]


— assuming your closure really is empty of statements.

Replies

() is the same as Void, or at least should be handled the same way.


func takesclosure(f: (foo: Any) -> Void) { f(foo: 1) }
let a = { (foo) -> () in print(foo) }
takesclosure(f:a)


compiles even though a closure returning () is sent to a function expecting a closure returning Void.


There is probably something else wrong here. Sometimes the error reporting in Swift is confused when it detects an errror and reports the wrong one.


I would try to be more specific when writing the closure, and actually write


(data: Data?, response: URLResponse?, error: Error?) -> Void


Being more specific is often a way to make the error reporting better.

Of course I know, given I use that same piece of code in many other places in my app. I also tried adding the esplicit ->Void annotation to no avail. I think it is a bug of the compiler that yet unfortunately does not allow my app to be compiled and run.

Try:


(a) putting a 'return ()' in the closure, or


(b) removing the [weak self]


— assuming your closure really is empty of statements.

Removing the weak annotation is impossible as thta would create a memory leak. I might try instead to enter the return command at the end of the closure, whatever that means.

Is the closure empty (devoid of non-declarative statements) as you originally posted?


— If yes, then removing [self weak] will have no effect, since the closure doesn't actually capture 'self'.


— If no, then you didn't give us a code fragment that actually produces an error, so how can anyone suggest a workaround?


You also didn't say which version of Xcode you're using.

In fact by adding return (), in the closure, for some reason I ignore, it compiles fine. Of course I did include in my sample the piece of code capturing self.

>> I did include in my sample the piece of code capturing self


You wrote:


let listTask = session.dataTask(with: theRequest, completionHandler:{[weak self](data, response, error) in
})


There is no code at all in this closure (that is, between "in" and the closing brace), so 'self' is not captured by the block. I also know this because, when I tried your code in a playground (Xcode 8 beta 6), I got a compiler warning that self wasn't captured by the block, so '[weak self]' was unnecessary.


>> for some reason I ignore, it compiles fine


Most likely because the explicit 'return' statement means that the compiler doesn't need to infer the type of value being returned by the closure, in order to compare it to the declared return type.


Various versions of Swift have had trouble with this for a while now, which is why the Xcode version matters, and why adding redundant code sometimes helps.

Removing the weak annotation is impossible as thta would create a memory leak.

This is a common misconception. The weak self dance is only necessary if all the strong references in the cycle are persistent. That’s not the case here. While the URLSessionDataTask does hold a strong reference to the closure you pass it, that reference is released when the task completes. As long as you actually start the task (by calling

resume()
), the task will eventually complete and that breaks the retain cycle.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

As said the problm went away by adding return () a the end of the cloure, o the weka issue becomes superflous. At any rate this is the full snippet of code:


        let configuration = URLSessionConfiguration.default
        let session = URLSession(configuration:configuration)
        let listTask = session.dataTask(with: theRequest, completionHandler:{[weak self](data, response, error) in
            self?.processData(data, error:error)
            return ()
        })
        listTask.resume()

As you see self is well captured as the function in most cases exits before the dataTask returns. I even had to use weak because the user might dismiss this controller even before the closure is called, so putting self to nil.

Next time, please post the full snippet the first time. It is very difficult for others to infer what you "of course know" and what you have hidden.

It is not always easy to select the right amount of code to post, from a single line of code, to a function, to the entire class: too much text tends to miss the issue, too less to create false answers. In my case I think I reasonably hit the spot given, of the two answers I was given, one was not applicable but the other fixed my problem for the good :-)

As said the problm went away by adding return () a the end of the cloure, o the weka issue becomes superflous.

Right. My point is that lots of folks advocate the weak self dance without really understanding what it does, and I’m trying to explain why it’s not necessary in many cases.

As you see self is well captured as the function in most cases exits before the dataTask returns. I even had to use weak because the user might dismiss this controller even before the closure is called, so putting self to nil.

Indeed. And this approach makes sense in some limited circumstances. However, in most cases it’s better to push your networking code down, out of your view controller layer and into a networking layer that’s tied to your model. Then your view controller just shows model objects and isn’t concerned with the networking.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

That would make very much Android programming... frankly I do not see so much the need to create so many layers in an object oriented environment but rather have in my full view the full piece of code I am working with. But of course this is a matter of taste. Somone like it horizontal, some othe ones like it vertical :-) It mins me of the bias, also being enforced in the WWDC, towards the have relationoship, oppsotie to the is one (property verus inheritance). OO theory has weel gaounded criteria to decide the relationships bwtween classes o to better model reality and I hold any attempt to steer somewhere for this make for not so easily maintanable code. But again this is a matter of taste.

… I do not see so much the need to create so many layers in an object oriented environment …

OK, I’ll give you a concrete example of why this is important. Imagine you have an iPhone app that shows a gallery of photos downloaded from the ’net. You might think that it’s OK to do your networking in your gallery view controller. However, consider what happens if the user:

  1. navigates in to your gallery view

  2. taps the back button to navigate out

  3. navigates in again

This results in two different view controllers, one in step 1 and another in step 3. The network requests issued by the view controller in step 1 get thrown away when the user switches out, and the view controller in step 3 has to start again from scratch. This is clearly less than ideal.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"