Swift.Bool isn't a Bool? - swift

I had a function
func login<Bool> (parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
//Do something
}
And whenever I called the completion handler like so
completion(false)
or
completion(true)
XCode kept telling me: "Cannot convert value of type 'Swift.Bool' to expected argument type 'Bool'"
Eventually, I removed the at the beginning of the function, and the error went away. I thought that was declaring the type for the function, but I'm frankly not sure what that means, or what <> does despite googling. I'm sure it's explained well, but I'm not grasping the concept from googling alone. And why is Swift.Bool not able to be converted to Bool. I was able to find that there is an objective C version of bool and I thought maybe it was asking for that, but that didn't work either. What does that mean a Bool is?

The syntax func login<Bool> defines a type parameter called Bool. It has nothing to do with Swift.Bool. It's just a name you've defined. It's the same as if you declared a local variable var Bool: String. You'd have a variable named Bool that is actually a String. Don't do that.
If you want the value to always be Bool, remove the type parameter. This isn't generic.
func login(parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
For details on the <...> syntax and generics see Generics in The Swift Programming Language.

Related

Cannot explicitly specialize a generic function when using closures

I have a function like this:
func register<T: Routable>(_ action: Action, withCallback callback: #escaping (T?) -> Void) {
notificationCenter.addObserver(forName: actionMap[action], object: nil, queue: .main, using: { notification in
let routable = T(userInfo: notification.userInfo)
callback(routable)
})
}
Where Routable is defined like:
protocol Routable {
init?(userInfo: [AnyHashable: Any]?)
}
When I try to use it, I receive
Cannot explicitly specialize a generic function
This is the usage:
controller.register<Navigate>(Action.navigate) { [unowned self] navigate in
// do something
}
Any idea to make the compiler happy?
I believe this is purely a syntax issue. You can't pass the type parameter directly like this. You need to "fill in the type hole" instead. To do that, you need to add the type to navigate:
controller.register(Action.navigate) { [unowned self] (navigate: Navigate?) in ... }
Sometimes that syntax is annoying because it buries the type. You can improve it by rewriting the signature of register this way:
func register<T: Routable>(action: Action, returning: T.type,
withCallback callback: #escaping (T?) -> Void)
You'd then call it this way:
controller.register(action: .navigate, returning: Navigate.self) {
[unowned self] navigate in
// ...
}
The returning parameter isn't directly used in the function. It just provides a more explicit way to specialize the function.
It's really hard to say without seeing a more complete code example... but basically what the compiler is telling you is "You told me you want the register function to be generic (because it has a type parameter) but then you are also trying to tell me exactly what type to use and I don't like that".
The point at which you are "explicitly specializ[ing]" the function is when you add a specific type parameter in the call:
controller.register<Navigate>...
# Right Here ^^^^^^^^^^
The compiler wants the flexibility to determine what type of register function to call. I suspect what you want is:
controller.register(Action.navigate) {...
Where you do not explicitly specialize the generic function but let the complier figure out which specialization to use.

escaping closure in swift

I have read a lot of material on stack overflow and I just cannot figure this one out:
I have been this line of code from an online source for hours and I just don't know why the closure that is being passed into a function is escaping, here is the code:
func composeFunction(functionA: #escaping (Int) -> String, functionB: #escaping (String) -> String) -> ((Int) -> String) {
return {
number in
functionB(functionA(number))
}
}
From apple's documentation, closures are escaping when:
1) Asynchronous operation that runs on a background thread
2) The closure is interactive with properties outside of it's scope (using self)
But I don't see those are happening, many help will be appreciated!
Thanks!
your func composeFunction returns a ((Int) -> (String)) and that is exactly a closure. Of course now this means functionA and functionB are going to be escaping because we don't know when and where this closure will be called. Moreover, this is because it needs to know if it should keep the reference to the objects passed in / being manipulated. For example, if all your closure parameters had (() -> Void) instead and you also returned (() -> Void) then it would not need to be escaping.
{
number in
functionB(functionA(number))
}
is a closure. Returning it causes both functionB and functionA to escape, because it becomes unknown at what point this closure will be called or deallocated.
This is different from just return functionB(functionA(number)), which causes the immediate invocation of both of those functions, and causes them to never escape the composeFunction context.

How to convert Objective-C block to Swift closure

I have a method that contains an block which defined in Objective - C:
+(void)getNewList:(NewListRequestModel *)model returnInfo:(void(^)(NewListResponseModel* resModel))retModel;
and I invoke it like:
[API getNewList:model returnInfo:^(NewListResponseModel *resModel) {
//code
}];
in Objective - C .
Now I want invoke it in Swift 3.2 :
API.getNewList(model, returnInfo: {(resModel: NewListResponseModel) -> () in
//my code
})
but I always got an error:
Cannot convert value of type '(NewListResponseModel) -> Void' to expected argument type '((NewListResponseModel?) -> Void)!'
can some one help me the right way to invoke it? thanks.
In Swift, closures can be very easily written. The compiler infers the parameter types and return type for you, so all you need to do is write the parameter name and in:
API.getNewList(model, returnInfo: {resModel in
//my code
})
You can also use the trailing closure syntax:
API.getNewList(model) {resModel in
//my code
}
The error occurs because resModel actually is of an optional type. iN the original Objective-C code, resModel was a pointer, which can be null. When this is bridged to swift, it turns into NewListResponseModel?.
Try this:
class func getNewList(model: NewListResponseModel
returnInfo: ((_ resModel: NewListResponseModel?) -> Void)?){
}
API.getNewList(model, returnInfo: {(resModel) in
//my code
})
//MARK: Class function to pass requestModel and get response model
class func getNewList(model: NewListRequesstModel, completion: #escaping (returnModel: NewListResponseModel) -> Void) {
//Your code to get new model for retrun
}
API.getNewList(model: newModelObject, completion: { (retunModelobject) in
//your code
})

Swift trailing closure stopped working when I moved the class into a Framework

I had a LocationManager class the performs various tasks and uses trailing closure.
Here is a method signature :
func getAdresseForLocation(location: CLLocationCoordinate2D, addressType: LocationManagerAddressType, completion: (Address?) -> Void)
For various reasons, I decided to move some file into a Framework, donc I declared my class and method public as follows :
public func getAdresseForLocation(location: CLLocationCoordinate2D, addressType: LocationManagerAddressType, completion: (Address?) -> Void)
But now I get a compilation error from the trailing closure :
Cannot convert value of type '(Address?) -> ()' to expected argument type '(Address?) -> (Void)'
I tried to change the return type to (), (Void), return Void or (Void) from the closure, nothing works.
Do you have any idea what's going on?
Thakns.
Try:
completion: ((Address)? -> Void))

How to disambiguate functions with differences only in parameter names in Swift

I have the following functions:
func moveThing(thing: AnyObject, toLeft length: Int) {}
func moveThing(thing: AnyObject, toRight length: Int) {}
However, when I pass one of the functions as a parameter, compiler complains about "Ambiguous use of 'moveThing'"
func exec(function: (AnyObject, Int) -> ()) {}
exec(moveThing) // Apparently ambiguous
exec(moveThing as (AnyObject, toLeft: Int) -> ()) // Still ambiguous
How can I solve the ambiguity?
Swift Evolution proposal SE-0021 addressed this by allowing moveThing(_:toLeft:) to disambiguate these functions, and it is implemented in Swift 2.2.
I know this is an old thread, but I ran into this related situation recently. Might help somebody.
TLDR
Ultimately I solved the problem by just wrapping the method call in a closure like this:
let cancel: (Text) -> Alert.Button = { .cancel($0) }
Long Winded Explanation
When I type Alert.Button.cancel (from the SwiftUI framework), auto-complete shows me these options:
cancel(action: (() -> Void)?) // 1
cancel(label: Text) // 2
cancel() // 3
cancel(label: Text, action: (() -> Void)?) // 4
Naturally I thought this bit of code should work:
let cancel: (Text) -> Alert.Button = Alert.Button.cancel(_:)
However, the compiler says Cannot convert value of type '((() -> Void)?) -> Alert.Button' to specified type '(Text) -> Alert.Button'. Apparently it translates that signature to mean method 1 instead of method 2.
As it turns out, method 2 does not actually exist. Looking at the actual declarations in Alert.swift we find:
public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button
So, cancel(label:) is rendered by auto-complete from cancel(_:action:) because the parameter action has a default value.
Conclusion: I made the mistake of assuming auto-complete was showing me individual method declarations. If the compiler tells you a method signature doesn't match what you expect, check the method declaration.
An interesting question! I don't think you can at the moment, as it seems that parameter names are not part of the function reference name, though I couldn't find anything from Apple's reference documentation that explicitly dictates this.
Of course, for this particular example, you can use
exec({ moveThing($0, toLeft: $1) } )
exec({ moveThing($0, toRight: $1) } )
but I see what you are after with the simplified example.