1

I tried to make use of the new Async/Await features in Swift 5.5 and tried the following code

let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(id)&country=at")

let (data, _) = try await URLSession.shared.data(from: url!)

let resultStruct = try jsonDecoder.decode(ResponseStruct.self, from: data)

Every time I execute this, the try await URLSession.shared.data(from: url!) part throws an error. If I catch it and print error.localizedString, I always get "cancelled". This happens with all different kinds of URLs. I tried to stick to the tutorials I found online, but what am I missing here?

EDIT: I forced the app into a runtime exception to get more details of the error:

Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSURLErrorDomain Code=-999 "cancelled"

As this post explains NSURLErrorDomain error code -999 in iOS, this error occurs when the SSL certificate of the server has issues, which I don't think is the case, as I am accessing the iTunes server or when the request gets canceled by anything else in my app, which looks like to be the case for me.

Bumblebee18
  • 53
  • 1
  • 9
  • You're not testing in a playground are you? – matt Jul 08 '21 at 19:54
  • No, I am coding in an iOS app project. – Bumblebee18 Jul 08 '21 at 19:59
  • Can't reproduce. I tried exactly your code and the first two lines succeeded just fine. There is something you are concealing from us. Voting to close as not being reproducible based on the information provided. – matt Jul 08 '21 at 20:22
  • 1
    Also judging from your other remarks you may be trying to combine this somehow with the Combine framework. That would be wrong. `Cancelled` is just what I would expect to see for a Combine pipeline that was never given a `.store` command. – matt Jul 08 '21 at 20:31
  • The combine one is an alternative I wrote first. I have two functions that do the same. They access the url and then in the result struct there is some data which I save into a dictionary, but in this function that point is never reached. The function that uses the combine framework works as expected. There also is not really anything else I could show. The code above is enclosed in a function that is marked with async and throws. – Bumblebee18 Jul 08 '21 at 21:05
  • The fact remains that your code as shown works fine for me. If you want help, show code that doesn't work fine. – matt Jul 09 '21 at 08:04
  • I can’t change the fact that the code shown above doesn’t work for me and I have no other code that doesn’t work. As stated in my EDIT, I assume that something asynchronous is interfering with my urlsession, but because I don’t know where to look for it, I unfortunately can’t post any other code. – Bumblebee18 Jul 09 '21 at 20:35
  • That's totally fine, I'm just saying there's not enough to go on at this point. – matt Jul 09 '21 at 21:13

2 Answers2

3

Change http to https. You cannot normally call insecure calls unless you add an exception to your Info.plist to disable App Transport Security.

There should be also a log from App Transport Security in your console.

Since ATS blocks the connection, the request gets cancelled.

See NSAppTransportSecurity for more info

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • Unfortunately that wasn't it. It is also interesting that if I use the .dataTaskPublisher() with a sink, it works without https and I added no exception to my Info.plist – Bumblebee18 Jul 08 '21 at 19:26
3

I encountered the same problem in a SwiftUI app. I was using the task view modifier to load data asynchronously and update the view based on the loading states.

As mentioned in the documentation:

If the task doesn’t finish before SwiftUI removes the view or the view changes identity, SwiftUI cancels the task.

If this is your case, make sure to update the UI only after the task completes.

Alternative solution

Alternatively you can use the onAppear view modifier (which doesn't cancel the Task) and run the task inside its body:

Color.clear.onAppear {
    Task {
        await viewModel.load()
    }
}