I have a little experience in Swift and facing a problem to pass a closure in a function as a parameter.
//1.
public func changeMyStatus(to f:?, _ completion:#escaping (_ isSucced:Bool)->()){
//
}
//2.
func goLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
//3.
func goNonLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
Now , I want to use first function in my controller and wants to pass second/third function as a parameter. Closure in first will return true/false depending on what returned by closure in second/third.
i)What will be the type I should put in first function?
Also I want to call first function from my class like this
changeMyStatus(to: goNonLive) { (isSuccess) in
}
please help
You need to change the changeMyStatus function signature and implementation like:
public func changeMyStatus(to f: (#escaping (Bool) -> ()) -> () , _ completion:#escaping (_ isSucced:Bool)->()){
f { (status) in
completion(status)
}
}
You can call these function like:
// goLive
changeMyStatus(to: goLive(_:)) { (status) in
print(status)
}
// goNonLive
changeMyStatus(to: goNonLive(_:)) { (status) in
print(status)
}
Your second and third function has a completion parameter with a type of : (Bool -> Void) -> Void
So in order to pass it to your first function, try this way :
public func changeMyStatus(to f: ((Bool) -> ()), _ completion:#escaping (_ isSucced:Bool)->()) { // Your body}
In Swift, you need to see a function as a type like Int, Double, String...
Related
Say that I have 2 functions:
functionA(#escaping closureA: ((Double) -> ())) {
// Some Code for function A
}
functionB(#escaping closureB: ((Double) -> ())) {
// Some Code for function B
}
If I want to call functionB from function A, how do I pass function A's closure parameter as argument to functionB's parameter?
Something that looks like this:
func A(#escaping closureA: ((Double) -> ())) {
// Some Code for function A
B(<trying to pass closureA>)
}
func B(#escaping closureB: ((Double) -> ())) {
// Some Code for function B
}
You need to escape the in parameter to the closure to start with and then when calling the closure sent to functionB you need to supply a value as argument
func functionA(closureA: (#escaping (Double) -> ())) {
functionB(closureB: closureA)
}
func functionB( closureB: (#escaping (Double) -> ())) {
closureB(3.2)
}
Example
functionA(closureA: {print($0 * 2.0)})
6.4
Try this example below.
func functionA(closure:(()->Void), completionHandler: #escaping (Double) -> Void) {
closure()
completionHandler(1.0)
}
func functionB(completionHandler: #escaping (Double) -> Void) {
completionHandler(2.0)
}
func nestedClosure() {
functionA(closure: {
functionB { (value) in
print("\(value)")
}
}, completionHandler: { (value) in
print("\(value)")
})
}
I am a Javascripter and I love using the not/negate function:
function not (predicateFunc) {
return function () {
return !predicateFunc.apply(this, arguments);
};
}
I am trying to do the same thing with swift:
func not <A> (_ f: #escaping (_ A: Any) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But I am getting errors like
generic parameter 'T' could not be inferred
and
Cannot convert value of type '(_) -> Bool' to expected argument type '(Any) -> Bool'
The outcome I am looking for is when I have a function like this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
I can just create a notEmpty function like this:
let notEmpty = not(isEmpty)
And then use it like
notEmpty([3,4,5]) // true
What am I doing wrong?
Using Any is a code smell. You can just extend Collection directly:
extension Collection {
var notEmpty: Bool {
return !isEmpty
}
}
[1, 3, 5].notEmpty // true
Your functional definition of not can work like this:
func not <A> (_ f: #escaping (_ a: A) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But to call it you would need something like this:
let arrayNotEmpty = not { (array: [Int]) in array.isEmpty }
arrayNotEmpty([1, 3, 5]) // true
You have two errors:
You're using A as both the type parameter and as the argument name.
You're using Any as the argument type instead of using the type parameter (A) as the argument type.
Try this:
func not<A>(predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
Note that in this version, I'm not using argument names for the predicate argument. You don't need an argument name in the declaration ((A) -> Bool) and I'm using the anonymous argument name ($0) in the body.
Okay, so you want to write this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
func not<A>(_ predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
let notEmpty = not(isEmpty)
And you get this error:
let notEmpty = not(isEmpty)
^ Generic parameter 'A' could not be inferred
The problem is that this code tries to create a generic closure, but Swift doesn't support generic closures.
That is to say, what would the type of nonEmpty be? It would be something like:
<A: Collection>(A) -> Bool
and Swift doesn't support that.
Assuming I have 2 functions foo and bar defined below.
func foo(completion: #escaping (Response) -> Void)
func bar(a: Int, completion: #escaping (Response) -> Void)
Then I have 2 different functions that use foo and bar
func doSomethingWithFoo() {
foo { response in
handleResponse(response)
}
}
func doSomethingWithBar() {
bar(a: 42) { response in
handleResponse(response)
}
}
doSomethingWithFoo and doSomethingWithBar are very similar. They do the exact same thing with response they get in the completion callback.
My question is: is there a way in Swift to generalize doSomethingWithFoo and doSomethingWithBar? Maybe something in line with the following.
func doSomething(<???>) {
<???> { response in
handleResponse(response)
}
}
<???> is a placeholder for passing either foo or bar or even any other function that also accepts a callback of type (Response) -> Void.
I'll appreciate any help/insights. Thanks.
You can declare a function like this :
func doSomething(fooBar: (_ completion: #escaping (String) -> Void) -> Void) -> Void {
fooBar(handleResponse)
}
Which you would call like this:
doSomething(fooBar: { bar(a: 42, completion: $0) })
doSomething(fooBar: foo)
I have this closure as variable:
public var cellClicked: (name: String, number: Int)?
How can I make it a trailing closure, so I can do something like:
cell.cellClicked!{
(str: String, n: Int) in
}
What you have declared is tuple not the closure, If you want to make closure declared it like this.
public var cellClicked: ((String,Int) -> ())?
And make call like this
cell.cellClicked = { (name, value) in
}
SWIFT 3.0
Try this.
public var cellClicked = (String, Int) -> Void
cell.cellClicked = {(str,n) in
}
You can use as below :
func myMethod(completionHandler: #escaping (_ param : type, _ param2 : type) -> Void)
Description of #escaping -> https://cocoacasts.com/what-do-escaping-and-noescaping-mean-in-swift-3/
I have these two swift classes:
class A {
static func list(completion: (_ result:[A]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
static func list(completion: (_ result:[B]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
Trying to compile this raise the error "overriding declaration requires an 'override' keyword" but just for the 'get' method of class B. 'list' method compiles fine. What is the difference between [B]? and B? for the compiler in this case?
Edit: Also notice that adding 'override' is not possible. I get the error 'Cannot override static method'.
In class B, the method list is a separate method from list in class A. They just share the same name, that's all.
The parameters of the two list methods are actually different:
// A.list
static func list(completion: (_ result:[A]?) -> Void) {
// B.list
static func list(completion: (_ result:[B]?) -> Void) {
A.list takes an argument of type (_ result: [A]?) -> Void while B.list takes a (_ result: [B]?) -> Void. The array type in the closure type's parameter list is different!
So you're not overridding anything, you're just overloading.
Note:
static methods can never be overridden! If you want to override a method, use class instead of static.
class A {
class func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
override class func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
In short, as per rule, static methods can't be overridden.