Swift closure generic parameters - swift

I have a protocol defined as
func get<T: ApiModel, TError: ApiModel>(url: String, params : [String : AnyObject]?, headers : [String : String]?, success:(T)->Void, error:(TError?, NSError)->Void) -> Void;
Trying to call it as
self.webClient.get("http://google.com", params: nil, headers: headers, success: { (response: ConcreteClass) in
}, error: { (errorModel:ConcreteErrorClass, error: NSError) in
})
This results in the following error:
'Cannot convert value of type (ConcreteClass) -> ()' to expected argument type '(_) -> Void'

In the declaration of the method you're calling, the error: closure has the first parameter of optional type (error:(TError?, NSError)->Void), but you declared it with non-optional type. That may be the reason (indeed, Swift sometimes produces pretty unrelated error messages).

Related

Is it possible to use Variadic Parameters within Closures?

Refurbished Question
Swift: Combining the use of Variadic Parameters with Closures
Is it possible to make a closure using variadic parameters?
func this(_ hello: (Int...) -> ()) {}
func that(_ yeah: Int...) {}
Here's what works: this(that)
Here's what didn't work:
this { foo in }, this { _ in }, this { }
I'm getting this error:
Cannot convert value of type '(_) -> ()' to expected argument type '(Int...) -> ()'
I even went so far as to change all Int... to Void...
I'm got the same results
With the additional warning of
When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'? Replace '(Void...)' with '()' However, replacing Void... with ()... did the trick
Simplified Problem
let _: (()...) -> () = { _ in }
Causes this error:
Cannot convert value of type '(_) -> ()' to specified type '(()...) -> ()'
Is it possible to work around this?
You need to include the type in the closure:
this { (foo: Int...) in }
The type-inference engine isn't quite powerful enough to figure out this case. I suspect it's related to SR-6030.

Cannot convert value of type '(_) -> ()' to expected argument type '(() -> ())?'

I've migrated my iOS Swift 3 application to Swift 4.
I got:
Cannot convert value of type '(_) -> ()' to expected argument type '(() -> ())?'
error trying to call this method:
self.aPIManager.registerDeviceId(deviceTokenStr,onSuccess:{
getRegister in
},
onError: { message in
AppUtility.hideLoading(self.window!)
})
Here is declaration of aPIManager.registerDeviceId:
open func registerDeviceId(_ deviceId: String, onSuccess successBlock: (() -> ())!, onError errorBlock: ((String?) -> Void)!) {
...
}
Here are the same functions in Swift 3 before moving to Swift 4:
open func registerDeviceId(_ deviceId: String, onSuccess successBlock:
(() -> Void)!, onError errorBlock: ((String?) -> Void)!) {
...
}
And here is the call:
self.aPIManager.registerDeviceId(deviceTokenStr,onSuccess:{
getRegister in
},
onError: { message in
AppUtility.hideLoading(self.window!)
})
I'm new to swift. I would be grateful if you provide me some information about this type of function declaration (function without name in it declaration).

Cannot convert value of type '[[String : Any]]' to expected argument type '[String : Any]'

here is my code:
var cardArray2 = [[String:Any]]()
insertDataIntoEntity("DeviceEntity", cardArray2)
the following method call is yielding this error:
Cannot convert value of type '[[String : Any]]' to expected argument type '[String : Any]'
here is my method signature:
func insertDataIntoEntity(_ entityTableName: String, _ arr: [String:Any]){
I tried to convert Any to Object, but that still did not work
try to change arr parameters to array of dictionary:
func insertDataIntoEntity(_ entityTableName: String, _ arr: [String:Any])
to
func insertDataIntoEntity(_ entityTableName: String, _ arr: [[String:Any]])

Casting to a specified generic function parameter

Let's say I have a Commander object that executes commands. The return type is not always the same and changes according to the command.
I'd like to be able to use a function that forwards a command to the Commander, tests if the result is of a certain type (passed as a parameter), before calling a success closure if the cast succeeded, and a failure closure otherwise.
I've tried using generic parameters with something like this:
func postCommand<T>(command: String, expectedResponseType: T, success: T -> Void, failure: (NSError?) -> Void) {
Commander.execute(command, completion: { (response: AnyObject?) in
guard let content = response as? T else {
failure(nil)
return
}
success(content)
})
}
Calling it that way
self.postCommand("command", expectedResponseType: [String: AnyObject], success: { (content: [String: AnyObject]) in
print("Success")
}) { (error: NSError?) in
print("Failure")
}
But I get an error from the compiler:
Cannot convert value of type '([String : AnyObject]) -> Void' to expected argument type '_ -> Void'
If I try to do the cast like this:
guard let content = response as? expectedResponseType
the compiler complains that expectedResponseType is not a type.
I can't figure out how to do that. Is it even possible?
The problem is not with the casting, but with the type of the expectedResponseType: parameter.
If you wish to pass a type to a function, you need to use the metatype type as the argument type. In this case, the expectedResponseType: parameter of your function should be of type T.Type – allowing you to pass in a type to define T.
func postCommand<T>(_ command: String, expectedResponseType: T.Type, success: (T) -> Void, failure: (NSError?) -> Void) {
// ...
}
You'll also need to use the postfix .self in order to refer to the actual type of whatever you pass into the expectedResponseType: parameter:
self.postCommand("command", expectedResponseType: [String: AnyObject].self, success: { content in
print("Success")
}) { error in
print("Failure")
}
Although you should note that the type of T can be inferred directly from the success closure you pass to the function:
func postCommand<T>(_ command: String, success: (T) -> Void, failure: (NSError?) -> Void) {
// ...
}
self.postCommand("command", success: { (content: [String: AnyObject]) in
print("Success")
}) { error in
print("Failure")
}

How to express Result<Value, Error: Errortype> in a method signature

I've been trying to make an Alamofire upgrade from 2.0 to 3.0. One of the methods contains this signature:
func standardResponse(request: NSURLRequest?, response: NSHTTPURLResponse?, result: Result<AnyObject>, success: (object: AnyObject?) -> Void, failure: (error: ServerError) -> Void)
There's an error pointing at Result<AnyObject>, stating that generic type 'Result' specialized with too few type parameters (got 1, but expected 2)
Alright, so I put in 2. According to the Alamofire 3.0 migration guide, Result has changed to accommodate an extra Error: ErrorType parameter. I tried this next:
Result<AnyObject, Error>
This time the error was that Error does not conform to protocol ErrorType.
So maybe this?
Result<AnyObject, Error: ErrorType>
No cigar. Please help me understand.
It looks like the second parameter has to be an object conforming to ErrorType.
So you could for example create your own error type with an enum like this:
enum MyErrorType: ErrorType {
case SomeError
case SomeOtherError
}
Then use it the way the compiler asks:
Result<AnyObject, MyErrorType>