Completion Handlers in Swift - swift

I'm fairly new at swift development and trying to get a handle on closures and completion handlers. I have a function with the following declaration inside a struct called ObjectData
func getData(id1:Int, id2:Int, completion: (dataObject? -> Void))
I am trying to call this function like
ObjectData.getData(1, id2: 2){
(let myObject) in
}
but i get the following error
Cannot invoke 'getData' with an argument list of type '(NSNumber, id2:
NSNumber, (_) -> _)'
Please can someone help

For better readability, change the header to this. Remember that you have to declare types, not variable names:
func getData(id1:Int, id2:Int, completion: (ObjectData?) -> (Void))
Now I personally use this syntax to use closures:
self.getData(1, id2: 1) { (data) -> (Void) in
// Some code executed in closure
}
If you want to study further, you can find full syntax of closures here (notice appropriate name of the website).
Hope it helps!

Far away from my Mac now, so I can't test, but try this:
ObjectData.getData(1, id2: 2, (dataObject) -> {
...code...
});
Also can't check now, but I think this also should work:
ObjectData.getData(1, id2: 2)(dataObject){
...code...
}

try to initialize your class first (ex. var objectData = ObjectData()) , and then call function with objectData.getData... it should work that way ..

In SWIFT 3,It is known as completion closure.
func getData(id1:Int, id2:Int, completion:#escaping(dataObject?) -> (Void)) {
//Do the stuff before calling completion closure
completion(value as? dataObject)
}
ObjectData.getData(id1:1, id2: 2,completion:{(data) -> (Void) in
//Do the completion stuff here
}

Related

Why does my struct become immutable in a method chain?

In Swift I am trying to implement a method "tap" similar to the method which exists in Ruby.
I've come up with the following example code:
private protocol Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self
}
private extension Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self {
block(&self)
return self
}
}
extension Array: Tap {}
var a = Array(repeating: "Hello", count: 5)
a.tap {
$0.append("5")
}.tap {
$0.append("7")
}
print(a) // (Expected) => ["Hello", "Hello", "Hello", "Hello", "Hello", "5", "7"]
I'm not super familiar with mutating functions, inout parameters, or Swift in general, but the code above looks like it should work to me. tap works as expected when it's not being included in a method chain. When I include it as part of a method chain, like in the above example, the Swift compiler complains:
Cannot use mutating member on immutable value: function call returns immutable value
Can anyone explain to me why this doesn't work? Can anyone provide a working solution and explain why that solution works?
Edit:
Another example usage would be:
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
tap is a convenience thing that comes from Ruby. I'm mainly interested in understanding why the types in my function aren't working out right.
The return self returns a copy of the original array, not the original array itself. Until this copy is stored as a var, it cannot be mutated. So, this would work:
var b = a.tap {
$0.append("5")
}
b.tap {
$0.append("7")
}
But not without storing b as a var first. Of course, you wouldn't create a b in the first place, you would just use a repeatedly as you already pointed out.
So, the issue is that you can accomplish tap once, but cannot chain taps. This is because the return of self is implicitly immutable, and you cannot call a mutating function on an immutable value. Changing tap to a non-mutating function could get you what you want:
private extension Tap {
func tap(_ block: (inout Self) -> Void) -> Self {
let copy = self
block(&copy)
return copy
}
}
var a = Array(repeating: "Hello", count: 5)
a = a.tap({$0.append("5")}).tap({$0.append("7")})
Because each invocation of tap( returns a copy of the original modified by the given block, you can call it on immutable types. That means that you can chain.
The only downside is that new a = in the beginning.

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
})

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.

How we write own function in swift with completionHandler

in objective c i write a method
-(void)loginApi:(NSMutableDictionary*)dict completion:(void(^)(NSDictionary *json,BOOL sucess))completion {
how we write same method
func loginApi(dict: NSMutableDictionary, completion: (json:NSDictionary,success: Bool) -> Void){
//Do whatever you want to do here
completion(json: dict, success: true) //This is just an example of how you can call
}
Give this a try. I think it should work. If not,let me know.
func loginApi(completion : (json: [Dictionary<String, String>, success: Bool]) -> [Dictionary<String Int>]) {
...
completion(...)
}
Although Previous answers will work I would suggest to alias it instead of typing the declaration every time (it also concern Objective c).
typealias CompletionHandlerType = (error:NSError ,response:AnyObject?) -> Void

How NSAnimationContext completionHandler work with Swift Language

i couldn't port this to swift, rest of NSAnimationContext straight forward.
[[NSAnimationContext currentContext] setCompletionHandler:^(void) {
//doSomething here...
}];
in docs it says var completionHandler: (() -> Void)! it did not mean anything to me.
Thank you.
() -> Void is the signature for a Swift closure that takes no parameters and returns nothing. Use it much like you would an ObjC block:
NSAnimationContext.currentContext().completionHandler = {
// do something here
}
Note that since it's declared as a property, you should set it like one -- ObjC getter/setter pairs don't translate to Swift.