Search code examples
swiftprotocolsswift5

Getting error when trying to use Result type with delegate


Im tring to make a network call and instead of using callback I try to use delegate instead.using Result type where .Sucsess is T: Decodable and .failure is Error. passing my model in the .Sucsess is working but when trying to pass an error I get a compile error "Generic parameter 'T' could not be inferred" what am I missing ?

protocol NetworkServiceDelegate: class {
    func decodableResponce<T: Decodable>(_ result: Result<T, NetworkError>)
}

let dataTask:URLSessionTask = session.dataTask(with: url) { (dataOrNil, responceOrNil, errOrNil) in
            if let error = errOrNil {
                switch error {
                case URLError.networkConnectionLost,URLError.notConnectedToInternet:
                    print("no network connection")
                    self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))
                case URLError.cannotFindHost, URLError.notConnectedToInternet:
                    print("cant find the host, could be to busy, try again in a little while")
                case URLError.cancelled:
                    // if cancelled with the cancelled method the complition is still called
                    print("dont bother the user, we're doing what they want")
                default:
                    print("error = \(error.localizedDescription)")
                }
                return
            }
            guard let httpResponce:HTTPURLResponse = responceOrNil as? HTTPURLResponse
                else{
                    print("not an http responce")
                    return
            }
            guard let dataResponse = dataOrNil,
                errOrNil == nil else {
                    print(errOrNil?.localizedDescription ?? "Response Error")
                    return }
            do{
                //here dataResponse received from a network request
                let decoder = JSONDecoder()
                let modelArray = try decoder.decode([Movie].self, from:
                    dataResponse) //Decode JSON Response Data
                DispatchQueue.main.async {
                    self.delegate?.decodableResponce(Result.success(modelArray))
                }
            } catch let parsingError {
                print("Error", parsingError)
            }
            print("http status = \(httpResponce.statusCode)")
            print("completed")
        }

this line generates the error, it dosnt metter if I pass my enum that cumfirms to Error or trying to pass the error from the dataTask

self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))

Solution

  • Well, you have two problems, having to do with the question "what type is this?" Swift is very strict about types, so you need to get clear about that.

    • .networkConnectionLost is not an Error. It is an error code. You need to pass an Error object to a Result when you want to package up the error. For example, URLError(URLError.networkConnectionLost) is an Error.

    • The phrase Result<T, NetworkError> makes no sense. Result is already a generic. Your job is to resolve the generic that it already is. You do that by specifying the type.

    So for example, you might declare:

    func decodableResponce(_ result: Result<Decodable, Error>)
    

    It is then possible to say (as tests):

    decodableResponce(.failure(URLError(URLError.networkConnectionLost)))
    

    or (assuming Movie is Decodable):

    decodableResponce(.success([Movie()]))
    

    That proves we have our types right, and you can proceed to build up your actual code around that example code.