Home > Back-end >  Invalid conversion from throwing function of type XXXX to non-throwing function type XXXX
Invalid conversion from throwing function of type XXXX to non-throwing function type XXXX

Time:10-20

I am stuck with this situation where I have a custom JSONDecoder struct which contains a private function to decode data, and another function which is exposed, and should return a specific, Decodable type. I would like these functions to throw successively so I only have to write my do/catch block inside the calling component, but I'm stuck with this error on the exposedFunc() function:

Invalid conversion from throwing function of type '(Completion) throws -> ()' (aka '(Result<Data, any Error>) throws -> ()') to non-throwing function type '(Completion) -> ()' (aka '(Result<Data, any Error>) -> ()')

Here is the code:

import Foundation
import UIKit

typealias Completion = Result<Data, Error>

let apiProvider = ApiProvider()

struct DecodableTest: Decodable {
    
}

struct CustomJSONDecoder {
    private static func decodingFunc<T: Decodable>(
        _ response: Completion,
        _ completion: @escaping (T) -> Void
    ) throws {
        switch response {
        case .success(let success):
            try completion(
                JSONDecoder().decode(
                    T.self,
                    from: success
                )
            )
        case .failure(let error):
            throw error
        }
    }
    
    static func exposedFunc(
        value: String,
        _ completion: @escaping (DecodableTest) -> Void
    ) throws {
        apiProvider.request {
            try decodingFunc($0, completion)
        }
    }
}


class CustomViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        do {
            try CustomJSONDecoder.exposedFunc(value: "test_value") { result in
                // Do something with result
            }
        } catch {
            print(error)
        }
    }
}

class ApiProvider: NSObject {
    func request(_ completion: @escaping (Completion) -> ()) {
        
    }
}

Thank you for your help

CodePudding user response:

This defines method that takes a non-throwing function:

class ApiProvider: NSObject {
    func request(_ completion: @escaping (Completion) -> ()) {
        
    }
}

So in all cases, this function must take a Completion and return Void without throwing. However, you pass the following:

    apiProvider.request {
        try decodingFunc($0, completion)
    }

This method does throw (note the uncaught try), so that's not allowed. You need to do something if this fails:

    apiProvider.request {
        do {
            try decodingFunc($0, completion)
        } catch {
            // Here you must deal with the error without throwing.
        }
    }
    }

CodePudding user response:

Not using concurrency features is making your code hard to understand. Switch!

final class CustomViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    Task {
      let result = DecodableTest()
      // Do something with result
    }
  }
}

extension DecodableTest {
  init() async throws {
    self = try JSONDecoder().decode(Self.self, from: await APIProvider.data)
  }
}

enum APIProvider {
  static var data: Data {
    get async throws { .init() }
  }
}
  • Related