1

I updated the Xcode to 14.3 and when I tried to run a project, I am getting this error: "Ambiguous use of 'dataTask(with:completionHandler:)'"

Do you know how I can fix this issue ?

extension URLSession: URLSessionProtocol {
    func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        return dataTask(with: url, completionHandler: completionHandler) as URLSessionDataTask
    }
}
protocol URLSessionProtocol {
associatedtype dataTaskProtocolType: URLSessionDataTaskProtocol
func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> dataTaskProtocolType

func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> dataTaskProtocolType }

This is my NetworkManager, where I got the following error:

"Value of type 'T.URLSessionDataTaskProtocol' has no member 'resume'"

class NetworkManager<T: URLSessionProtocol> {

let session: T

required init(session: T) {
    self.session = session
}

/// Errors that will be generated by the HTTPManager
enum HTTPError: Error {
    case invalidURL
    case noInternet
    case invalidResponse(Data?, URLResponse?)
}

///  Get data through an API call using a URL, returning a result type
///
/// - Parameters:
///   - url: A URL represting the location of the resource
///   - completionBlock: A completion closure returning the result type
public func get(url: URL, completionBlock: @escaping (Result<Data, Error>) -> Void) {
    // make sure we pull new data each time
    let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60)
    
    let task = session.dataTask(with: request) { data, response, error in
        guard error == nil else {
            completionBlock(.failure(error!))
            return
        }
        
        guard
            let _ = data,
            let httpResponse = response as? HTTPURLResponse,
            200 ..< 300 ~= httpResponse.statusCode else {
                if let data = data {
                    completionBlock(.success(data))
                } else {
                    completionBlock(.failure(HTTPError.invalidResponse(data, response)))
                }
                return
            }
        // if passed guard
        if let data = data {
            completionBlock(.success(data))
        }
    }
    task.resume()
}}
Louiza A
  • 23
  • 6
  • What exactly are you trying to do? What is `URLSessionProtocol`? – Sweeper May 01 '23 at 10:06
  • 1
    Did this actually work before Xcode 14.3? Swift's name resolution rules must have changed... – Sweeper May 01 '23 at 10:11
  • It's hard to see what's the difference between the two methods: the one already existing in `URLSession` and the one you are calling, so I guess the compiler doesn't know which call in the `return` – Larme May 01 '23 at 10:11
  • @Sweeper yes it worked before Xcode 14.3 – Louiza A May 01 '23 at 10:29
  • I updated my question with the URLSessionProtocol – Louiza A May 01 '23 at 10:31
  • Your are redefining dataTask in your extension. May be you made a mistake in the return type ? – Ptit Xav May 01 '23 at 10:35
  • I see. Then `URLSession` should conform to the protocol just by adding `typealias dataTaskProtocolType = URLSessionDataTask`. The sendabilities won't match though, so you might want to add some `@Sendable`s to the protocol methods. – Sweeper May 01 '23 at 10:35
  • @PtitXav but it was working before the Xcode update – Louiza A May 02 '23 at 05:50
  • @Sweeper can you write what you recommend as an answer to try it please ? – Louiza A May 02 '23 at 05:51
  • @LouizaA It's very similar to Daniel T's answer. That works for me. Your error message you got must be caused by some other part of your code, which you have not shown. – Sweeper May 02 '23 at 05:58
  • @Sweeper I updated my question with the NetworkManager – Louiza A May 02 '23 at 06:06

1 Answers1

1

Here's the fix:

protocol URLSessionDataTaskProtocol {
    func resume()
}

protocol URLSessionProtocol {
    func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
    func dataTask(with url: URL, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSessionDataTask: URLSessionDataTaskProtocol { }
extension URLSession: URLSessionProtocol {
    func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol {
        self.dataTask(with: request, completionHandler: completionHandler) as URLSessionDataTask
    }

    func dataTask(with url: URL, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol {
        self.dataTask(with: url, completionHandler: completionHandler) as URLSessionDataTask
    }
}
Daniel T.
  • 32,821
  • 6
  • 50
  • 72
  • I am getting this error: "Value of type 'T.URLSessionDataTaskProtocol' has no member 'resume'" – Louiza A May 01 '23 at 13:07
  • After your edit, I am getting the following error: "Ambiguous use of 'dataTask(with:completionHandler:)'" on the following line: "let task = session.dataTask(with: request, completionHandler: { data, response, error in " – Louiza A May 02 '23 at 06:26
  • I found the solution! The correct format is the following: " let task: URLSessionDataTask = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in " – Louiza A May 02 '23 at 06:47