Swift incorrect closure in function declaration - ios

I am trying to use Moya Networking in my project. I am using this example. The example is making moya request to connect to server in view controller on Line 56 which is below and using callback methods in Line 72 and Line 78
func uploadGiphy() {
provider.request(MultiTarget(Giphy.upload(gif: Giphy.animatedBirdData)),
callbackQueue: DispatchQueue.main,
progress: progressClosure,
completion: progressCompletionClosure)
}
I want to write this function in NetworkHelper.swift instead of my view controller but, use its two callback methods (Line 72 and Line 78) in my view controller.
So I wrote the function in NetworkHelper:
static func getUsers(amount:Int=2,
gender:Gender = .Male,
success successCallback: #escaping ([UserModelMain]) -> Void,
error errorCallback: #escaping (Swift.Error) -> Void,
failure failureCallback: #escaping (Moya.MoyaError) -> Void,
progress progressClosure: #escaping (Moya.ProgressResponse) -> Void,
progressCompletion progressCompletionClosure: #escaping (Moya.Completion) -> Void)
{
provider.request(.getUsers(amount: amount, gender: gender),
callbackQueue: DispatchQueue.main,
progress: progressClosure,
completion: progressCompletionClosure)
}
Its showing error:
Cannot convert value of type '((Result) -> Void)
-> Void' to expected argument type 'Completion' (aka '(Result) -> ()')
I think I am writing my function getUsers wrong. I messed it up. I am weak at closures.
Kindly help.
Source Code of request function from Moya networking library:
/// Designated request-making method.
Returns a `Cancellable` token to cancel the request later.
#discardableResult
open func request(_ target: Target,
callbackQueue: DispatchQueue? = .none,
progress: ProgressBlock? = .none,
completion: #escaping Completion) -> Cancellable {
let callbackQueue = callbackQueue ?? self.callbackQueue
return requestNormal(target, callbackQueue: callbackQueue, progress: progress, completion: completion)
}

Moya.Completion is already a completion block. You just need to pass Moya.Completion as an argument, instead of (Moya.Completion) -> Void.
progressCompletion progressCompletionClosure: #escaping Moya.Completion)
Your current code, like the error suggest, is sending ((Result) -> Void) -> Void

Related

Completion handler in function

I have a function that looks like this, and I have tried to add a completionHandler in the code below:
func getValueFromAPI(completionHandler: (_ result: Bool) -> Void){
apii.getVehicle(id!).done {
(vehicle: Vehicle) -> Void in
print("ggg.state: \(vehicle.state!)")
print("ggg.state: \(vehicle.displayName!)")
apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
let entryBattery = (extendedVehicle.chargeState?.batteryLevel)!
let entryCarState = (extendedVehicle.state)!
print("entryBattery: \(entryBattery)")
print("entryCarState: \(entryCarState)")
completionHandler(true)
}.catch { (error) in
print("ERROOOOR: \(error)")
}
}.catch { error in
print("errorr: \(error)")
}
}
I have already tried to add a complete handler, but I get the following error on these lines:
Line: apii.getVehicle(id!).done {
Error: Escaping closure captures non-escaping parameter 'completionHandler'
Line: apii.getAllData(vehicle).done { (extendedVehicle: VehicleExtended) in
Error: Escaping closure captures non-escaping parameter 'completionHandler'
What am I doing wrong here, and how can I fix this?
I am using Swift 5.
You need to declare your completionHandler to be an escaping closure. E.g.:
func getValueFromAPI(completionHandler: #escaping (Bool) -> Void) {
...
}
Note the #escaping qualifier.

How to call a function instead of implementing closure

I have this function
func performNetworkRequest(timeout: Int, completion: (Result<Response, Error>) -> Void) {
// ....
}
I want to be able to call performNetworkRequest without writing the closure, but to pass an function to do the logic's over there.
something like :
func onNetwotkResponse(result: (Result<Response, Error>) -> Void) {
}
performNetworkRequest(timeout: 60, completion: onNetwotkResponse)
How can I achieve this?
Thanks
The type of closure is:
(Result<Response, Error>) -> Void
which means
A function that accepts a Result<Response, Error> and returns Void.
This means that your onNetwotkResponse function should accept Result<Response, Error>, rather than (Result<Response, Error>) -> Void:
func onNetwotkResponse(result: Result<Response, Error>) {
}

Store completion handler and call success/error later

I have a protocol/function in my class which is below,
func getMovieList(completionHandler: #escaping (Result<[String], Error>) -> Void) { }
When the above method is called, I want to store the completion handler and call the success/error in the latter part.
I tried creating a typealias like below,
typealias AlbumListCompletionHandler = (((Result<[String], Error>)) -> Void)?
And in my class,
var completionHandlerObj: AlbumListCompletionHandler
func getMovieList(completionHandler: #escaping (Result<[String], Error>) -> Void) {
completionHandlerObj = completionHandler
/...
.../
}
But I wonder how do I call the success/error blocks in completionHandlerObj, kind of struck here. Can anyone help me with this ?
It should work like this
completionHandlerObj(.success(["",""]))
completionHandlerObj(.failure(ErrorObject))

How to create closure with specific typealias in swift?

I'm using the swift package OnboardKit and it requires a specific closure type that I cannot figure out.
The class OnboardPage requires a type OnboardPageAction for the parameter action.
public typealias OnboardPageCompletion = ((_ success: Bool, _ error: Error?) -> Void)
public typealias OnboardPageAction = (#escaping OnboardPageCompletion) -> Void
OnboardPage(title: "Title",
description: "description",
action: action)
This is my latest attempt, I tried several variations along those lines.
let action: ((_ success: Bool, _ error: Error?) -> ()) = {_,_ in
print("help")
}
XCode fails with the error message:
Cannot convert value of type '(Bool, Error?) -> Void' to expected
argument type 'OnboardPageAction?' (aka 'Optional<(#escaping (Bool,
Optional) -> ()) -> ()>')
What am I doing wrong here? Is the mistake in my closure definition or in the way I use it in the OnboardPage() call? Thanks :)
(I learned details about closures here Closures Swift How To, but I am not able to define the right closure type that the package expects)
Judging from the context, I guess that the purpose of the action parameter is to allow you run some code when an OnboardPage is presented. This "action" might take some time (it might not finish when action returns), so it gives you a completion handler parameter that you can call to indicate that what you want to do is done.
If you just want to print Hello, you can just call the parameter after you printed hello to indicate that you finished what you want to do:
OnboardPage(title: "Title",
description: "description",
action: { completion in
print("Hello")
completion(true, nil)
})
or simply
OnboardPage(title: "Title",
description: "description") {
print("Hello")
$0(true, nil)
}
The first argument indicates whether the action is successful, the second contains an optional error for when it fails.
The declaration of an action should look like this to match the defintions provided:
let action: OnboardPageAction = { (_ closure: ((_ success: Bool, _ error: Error?) -> Void)) in
print("action")
}

'CompletionHandler' is ambiguous for type lookup in this context

I recently joined a new project and started working on iOS app codebase. However, with latest Xcode 10, the code no longer compiles.
protocol NetworkClientType {
associatedtype CompletionHandler
static func intoRequest(_ url: URL?) -> URLRequest?
}
extension NetworkClientType {
typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
static func intoIncompleteURLSessionDataTask(_ request: URLRequest) -> (CompletionHandler) -> URLSessionDataTask {
return { completion in URLSession(configuration: .default).dataTask(with: request, completionHandler: completion) }
}
}
Then on line 10 (static func intoIncompleteURLSessionDataTask...), the compiler error says 'CompletionHandler' is ambiguous for type lookup in this context
Does anyone know how to resolve this? I have googled around and couldn't find working solutions.
Change
extension NetworkClientType {
typealias CompletionHandler = (Data?, URLResponse?, Error?) -> Void
to
extension NetworkClientType
where CompletionHandler == (Data?, URLResponse?, Error?) -> Void {

Resources