Swift - Call completion handler from a second function - swift

thanks for reading this, i hope you can understand my problem. Basically what i would like to do is this:
private func doGet(path:String, body:Dictionary, completion: #escaping (JSON?, Bool) -> Void) {
completion(data, bool)
}
func getData(body){
return doGet("/api/data", body: body)
}
// The function gets called in another class
getData(data){ (data, bool)
// do something with data
}
I know this code doesnt work but thats what i would like to do. I dont want to call doGet from the other class i want to have a function in between. Maybe this is not possible. Please let me know if i didnt make myself clear and thanks in advance. :)

getData also needs to have a completion handler parameter, since it too returns the results asynchronously.
So, you'd have something like this:
getData(body: SomeType, completion: #escaping (Data, Bool) -> Void) {
doGet(path: "/api/data", body: body) { (param1, param2) in
// turns param1 and param2 into parameters to invoke
// the completion handler with
completion(data, true)
}
}

Related

how to pass a callback function in another function in swift?

so i'm doing my first app,
and i want to do a function that will be a uniform funciton to sevral places in the system, and not belong to only one specific class.
Is there a way for me to pass a callback function as a parameter to another function ?
here is just a demonstration of what i mean.
ClassA {
func classAcallbackFunction (displayString: String) {
print (displayString)
}
ClassB().classBFunction(classAcallbackFunction())
}
ClassB {
func classBfunction (myCallbackfunc: func) {
mycallbackfunc("all is working !!!")
}
}
The parameter you have declared is not correct. Replace it with something like this:
func classBFunction(_ completion: (String) -> Void) {
completion("all working")
}
Like shared by regina_fallangi in the comments, callbacks are usually called completion handlers, which is why I replaced the names accordingly.
Extra Credit:
If you only want to optionally pass a function, you could do this:
func classBFunction(_ completion: ((String) -> Void)? = nil) {
completion?("all working")
}
Now you could also just call classBFunction().

Closures vs returning an value/object from a function

I'm currently learning Swift(4)/iOS programming. I'm fairly new to OOP, but do have experience in Functional programming. There's one concept that confuses me somewhat...
In the courses/examples I followed a function mostly looks like this:
func getUsername(forUid uid: String, handler: #escaping (_ username: String) -> Void) {
//Do stuff
handler("MyName")
}
The name is passed by the closure, I hardly ever see a function like this:
func getUsername(forUid uid: String) -> String) {
//Do stuff
return "MyName"
}
Is the second way deprecated, or is there still a use for such a function. When and why do we use the first variant ?
We use the first variant for asynchronous programming. For example, see
func getUsername(forUid uid: String, handler: #escaping (_ username: String) -> Void) {
DispatchQueue.main.async {
// do some asynchronous stuff
handler("MyName")
}
}
Note handler has to be inside the async closure or else the handler will be called immediately because async does not block. Now if we used return instead of handler, there will be a compile error because your function doesn't return any value, so to fix the compile error it has to be in the function level (not in the async block). If it's not in the async block, it will be returned immediately (same as the second handler case above, so you must use closures if you are doing asynchronous tasks. However, if you are not using asynchronous stuff, you can safely use the second variant in your code.
In addition to asynchronous programming, closures are used in synchronous programming too, for example, the map function uses a closure as a parameter to define how should the object be mapped.
Of course it's not deprecated.
You should use closures for async tasks otherwise return value.
It is easier to get it with an example. Here's I get some places from an API:
func getPlaces(onSuccess: #escaping(_ places: [Place]?) -> Void, onFailure: #escaping(Error, _ title: String?, _ message: String?) -> Void) {
//perform API request...
//[...]
//...
// Session
session.dataTask(with: requestURL) { (data, response, error) in
guard error == nil else {
//handling Error
onFailure(error!, "Error", error?.localizedDescription)
group.leave()
return
}
//...
//handling succes
else {
var places: [Place] = []
places = responseJson.places!
onSuccess(places)
}
group.leave()
}.resume()
}
group.wait()
return
}
As you can see I want to handle success and error. Here's how I use it:
APIManager.shared.getPlaces(onSuccess: { (places) in
//handling success
}
}) { (error, title, message) in
DispatchQueue.main.async {
self.present(getAlertFromError(title: title, message: message), animated: true)
}
}

Wait for unpredictable data before performing a completion a block inside method

I have a function that does some work and call completion. Something like this
func doStuff(completion: (Bool) -> ()) {
performWork()
completion(true)
}
The problem is that performWork triggers some process that receives result in other method. And depending on this result I need call completion with success or not based on data from previous method.
Is there any possible solution ? Method doStuff can not be modified and I don't have access to performWork() its third party, I can only call it.
You should save completion in a variable in the scope of your class and execute it in the delegate method of your API.
var doStuffCompletion: (Bool) -> ()!
func doStuff(completion: (Bool) -> ()) {
performWork()
doStuffCompletion = completion
}
func apiStuffFinished(success: Bool) {
doStuffCompletion(success)
}

Swift 3 - How can i define callback function as parameter

want to create global http request function/extension with Alamofire it's like
function Request(requestPath:String, requestParams:Any, onComplate:Void) {
// stuff here, when async request complate i want to call onComplate function
// like C# method.Invoke() or func.Invoke()
}
You can just pass the closure(function) as parameter
swift
func request(requestPath:String, requestParams:Any, callback:((Result) -> Void)) {
...
}
Where Result will be the type of your response.
Thanks for reply but finally solution
class HttpRequest<Request, Response>
{
private var serviceBase:String = "http://192.168.1.1/api";
func request(path:String, model: Request, success: #escaping((_ response: [Response]?) -> ()), failure: #escaping ((_ error:String) -> ()) {
// code here..
}
}
you can use Closures
please refer document below.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
This will be the best option

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