Swift 3 - How can i define callback function as parameter - swift

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

Related

Swift - Call completion handler from a second function

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

converting a function that accepts closures to accept functions

I have a function that accepts a closure as an argument
public func createSelector<Input: Hashable, Output, A>(_ selectorA: #escaping (Input) -> A, _ combine: #escaping (A) -> Output) -> (Input) -> Output {
return memoize({ combine(selectorA($0)) })
}
A use case is something like this
let getStore = { (store: AppState?) -> FeedState? in store?.feed }
let getFeedItems = createSelector(getStore) { (state: FeedState?) -> [Post] in state?.posts ?? [] }
This is used to select a piece of state from a ReSwift store and return results after running a memoize function.
Xcode seems to struggle with auto complete when using this closure pattern
When I expect it to be able to show props as follows
It was suggested to me that writing my closures as functions will prevent this issue.
As such, I am trying to convert the above function to work with functions to see if this helps.
I am confused how the above pattern can be refactored to support functions instead and would appreciate any advice.
Thank you.
Edit:
This is an example attempt:
func getStoreFunc(_ state: AppState?) -> FeedState? {
return state?.feed
}
func getFeedItemsFunc(_ fn: #escaping (AppState?) -> FeedState?) -> [Post] {
return createSelector(fn, { (state: FeedState?) -> [Post] in
return state?.posts ?? []
})
}
However this produces and error of
Cannot convert return expression of type '(AppState?) -> [Post]' to
return type '[Post]'
on my getFeedItemsFunc
Your createSelector(_:_:) function takes two closures. However, Swift lets you pass functions in place of closures so long as the types match.
In your code, you declared one closure beforehand (getStore) and wrote the other one using trailing closure syntax when you called the createSelector(_:_:) method. However, functions can't be declared using this syntax. So I created a function called getPostsFunc(_:) that replaces your second closure.
// corresponds to:
//let getStore = { (store: AppState?) -> FeedState? in store?.feed }
func getStoreFunc(_ state: AppState?) -> FeedState? {
return state?.feed
}
//corresponds to:
//{ (state: FeedState?) -> [Post] in state?.posts ?? [] }
func getPostsFunc(_ state: FeedState?) -> [Post] {
return state?.posts ?? []
}
//This is the same as your `getFeedItems`
let getFeedItems = createSelector(getStoreFunc, getPostsFunc)
Hope this helps!

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 3: Inheritance from non-named type

I have the following SSCIE:
protocol Foo {
associatedtype Bar
associatedtype Baz: (Self.Bar) -> Void
var currentValue: Bar { get }
}
That I want to use like this:
func call<T: Foo>(foo: T, callback: #escaping T.Baz) {
DispatchQueue.main.async {
callback(foo.currentValue)
}
}
But it fails to compile, with the error:
Inheritance from non-named type '(`Self`.Bar)'
This also fails to compile when I use (Bar) -> Void and (Foo.Bar) -> Void.
Sadly, Googling this didn't come up with any useful results.
Does anyone have any idea what this error means, what I'm doing wrong, and how to correct it?
Associated types in Swift 3 can only be "is-a"-constrained. So your Bar is required to be an Any. Which, by the way, is not much of a constraint ;). In other words, you can remove it.
However, (Self.Bar) -> Void is a function type and you can't constrain an associated type like this.
If you want to define a callback type, you can use a typealias:
protocol Foo
{
associatedtype Bar
typealias Callback = (Self.Bar) -> Void
var currentValue: Bar { get }
func f(callback: Callback) -> Void
}
Using #escaping does not currently work in a typealias (see SR-2316 and its various duplicates). This is a bug that was supposed to have a fix soon (as of August 2016). So you will have to spell it out for now:
func call<T: Foo>(foo: T, callback: #escaping (T.Bar) -> Void) {
DispatchQueue.main.async {
callback(foo.currentValue)
}
}
Update: As Hamish suggested, I filed SR-4967. I'll update this post as soon as there is any news about it.
As already mentioned, function types can't be used as associated types.
Try this instead:
func call<T: Foo>(foo: T, callback: #escaping (T.Bar) -> Void) {
...
}
and using this design you can mix-and-match function types (for the callback arg) for each specific helper function (call in your example) you come up with.

How to create function with two closures as params in Swift?

I need to translate such a func from Objective-C to Swift language. But can't find an example and can't get how to send 2 closures into func in Swift.
For example, original function in Objective-C:
- (void)getForDemoDataWithToken:(Token *)token
onSuccess:(void(^)(NSArray *demoData))success
onFailure:(void(^)(NSError *error))failure {
}
I know to send 1 closure as param:
getForDemoDataWithToken(token) {(success: String) -> Void in
// some code here
print(success)
}
But, how to send two closures?
Thank you
What about this?
Declaration
func getForDemoDataWithToken(
token: Token,
onSuccess: (demoData:NSArray?) -> (),
onFailure: (error:NSError?) -> ()) {
}
Invocation
getForDemoDataWithToken(Token(),
onSuccess: { (demoData) -> () in
},
onFailure: { (demoData) -> () in
}
)
A more Swifty approach
I usually see Swift code where only one closure is used. So instead of 2 distinct onSuccess and onFailure closures you could have just completion.
Next we should remember that NSArray is compatible with Swift but it's not the Swiftest way to use an array.
Let's see an example where the 2 concepts above are applied.
func getForDemoData(token:Token, completion:(data:[Foo]?, error:NSError?) -> ()) {
}
You can invoke it with the trailing closure syntax.
getForDemoData(Token()) { (data, error) -> () in
if let data = data where error == nil {
// success!
} else {
// oh no... something wrong here
}
}
You should pass the closures as normal parameters, like this:
func acceptsTwoClosures(
onSuccess onSuccess: (success: String) -> Void,
onFailure: (failure: String) -> Void) {
onSuccess(success: "Ook")
onFailure(failure: "Eek")
}
acceptsTwoClosures(
onSuccess: { print("Success: \($0)") },
onFailure: { print("Failure: \($0)") }
)
// In the playground the above prints:
//
// Success: Ook
// Failure: Eek
The way that you used in the question is called trailing closure, and it only works for the closures that are the last arguments in the function signature.
From the documentation:
If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports.
For example, you could also re-write my suggested snippet from above like this:
acceptsTwoClosures(onSuccess: { print("Success: \($0)") }) {
print("Failure: \($0)")
}
.. as you can see, I can pass the second (i.e. the last) closure outside of acceptsTwoClosures call as a trailing closure, but I still have to pass the first one as a normal parameter.