Escaping block as argument to an escaping argument - swift

I'd like to schedule jobs, and pass a completion handler to each job like so:
class Scheduler {
var jobs = [(() -> ()) -> ()]()
func schedule(block: #escaping (() -> ()) -> ()) {
jobs.append(block)
}
func run() {
if !jobs.isEmpty {
let job = jobs.removeFirst()
// Run the next job when this job is done
job { self.run() }
}
}
}
func test() {
let s = Scheduler()
s.schedule { next in
// Perform some work, this requires `next` to be escaping:
DispatchQueue.main.async(execute: next)
}
// later
s.run()
}
The swift compiler does not like that next is escaping, without being marked as such:
main.swift:22:43: error: passing non-escaping parameter 'next' to function expecting an #escaping closure
DispatchQueue.main.async(execute: next)
^
main.swift:21:28: note: parameter 'next' is implicitly non-escaping
Scheduler().schedule { next in
^
The obvious change would be to mark the next argument as escaping:
func schedule(block: #escaping (#escaping () -> ()) -> ()) {
But now the compiler seems to be mistakenly mark the block as non-escaping:
main.swift:9:21: error: using non-escaping parameter 'block' in a context expecting an #escaping closure
jobs.append(block)
^
main.swift:8:19: note: parameter 'block' is implicitly non-escaping
func schedule(block: #escaping (#escaping () -> ()) -> ()) {
^
#escaping
Is this a known compiler issue?
Are there workarounds?

Related

Escaping Closure captures non-escaping parameter dispatch

I am getting the error: Escaping closure captures non-escaping parameter dispatch. This error is coming on MovieService().getMovies line.
typealias ActionCreator = (_ dispatch: (Action) -> (), _ getState: () -> AppState) -> ()
func fetchMovies() -> ActionCreator {
return { dispatch, getState in
MovieService.getMovies(url: "http://www.omdbapi.com/?s=Batman&page=2&apikey=YOURKEY") { result in
switch result {
case .success(let movies):
if let movies = movies {
dispatch(.populateMovies(movies))
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
Any ideas?
As closures documentation states:
A closure is said to escape a function when the closure is passed as
an argument to the function, but is called after the function returns.
When you declare a function that takes a closure as one of its
parameters, you can write #escaping before the parameter’s type to
indicate that the closure is allowed to escape.
By default a closure is nonescaping like your dispatch parameter, but you are calling it inside an escaping closure which probably is the closure that you pass as a parameter in getMovies function.
The solution is simple, just add #escaping before the dispatch parameter type:
typealias ActionCreator = (_ dispatch: #escaping (Action) -> (), _ getState: () -> AppState) -> ()

Pass a closure in a function

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...

How to fix : "passing non-escaping parameter to function expecting #escaping closure"

I'm experimenting usage of closurse for First Order Predicate calculus, and
I intend to define the following function :
func ASSUM<U, V>(p: #escaping Pred<U>) -> (Pred<U>) -> Pred<(U, V)> {
return { q in AND1(p: p, q: q) }
}
that takes as parameter a predicate p: Pred<U>, where Pred<U> is a typealias for (T) -> Bool:
typealias Pred<T> = (T) -> Bool
The return of ASSUM is a Predicate transformer closure of type (Pred<U>)->Pred<(U,V)>.
However the compiler return the following error :
Passing non-escaping parameter 'q' to function expecting an #escaping closure
I understand that the function AND1 as defined requests an escaping parameter :
func AND1<U, V>(p: #escaping Pred<U>, q: #escaping Pred<V>) -> Pred<(U, V)> {
return { (x, y) in (p(x) && q(y)) }
}
but I did not succeed in explicitly making q in { q in AND1(p: p, q: q) } escaping.
How can I fix this?
You must explictly add the #escaping attribute to the argument of the return type closure of ASSUM:
typealias Pred<T> = (T)->Bool
func AND1<U, V>(p: #escaping Pred<U> , q: #escaping Pred<V>) -> Pred<(U, V)> {
return { (x,y) in (p(x) && q(y)) }
}
func ASSUM<U, V>(p: #escaping Pred<U>) -> (#escaping Pred<V>) -> Pred<(U, V)> {
/* ^ note: I believe you
want V here, not U */
return { AND1(p: p, q: $0) }
}
In the returned closure, q (anonymous $0 argument) is correctly inferred as #escaping (and needn't be explicitly marked as such, as pointed out by #Hamish, thanks!).
Note also that the generic type V in ASSUM must be inferred by explicit type annotation (or conversion) by the caller, as it is not included in any of the arguments to ASSUM.
/* example usage */
let foo = { $0 < 2 }
let bar = { $0 != "bar" }
let fooAnd: (#escaping Pred<String>) -> Pred<(Int, String)> = ASSUM(p: foo)
let fooAndBar = fooAnd(bar)
print(fooAndBar((1, "foo"))) // true
print(fooAndBar((1, "bar"))) // false
print(fooAndBar((2, "foo"))) // false
Finally, ALLCAPITAL function names is not in line with the Swift naming convention: you should prefer camelCase naming instead (see e.g. the Swift API guidelines for additional details).

Swift override static method compile error

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.

Escaping Closures in Swift

I'm new to Swift and I was reading the manual when I came across escaping closures. I didn't get the manual's description at all. Could someone please explain to me what escaping closures are in Swift in simple terms.
Consider this class:
class A {
var closure: (() -> Void)?
func someMethod(closure: #escaping () -> Void) {
self.closure = closure
}
}
someMethod assigns the closure passed in, to a property in the class.
Now here comes another class:
class B {
var number = 0
var a: A = A()
func anotherMethod() {
a.someMethod { self.number = 10 }
}
}
If I call anotherMethod, the closure { self.number = 10 } will be stored in the instance of A. Since self is captured in the closure, the instance of A will also hold a strong reference to it.
That's basically an example of an escaped closure!
You are probably wondering, "what? So where did the closure escaped from, and to?"
The closure escapes from the scope of the method, to the scope of the class. And it can be called later, even on another thread! This could cause problems if not handled properly.
By default, Swift doesn't allow closures to escape. You have to add #escaping to the closure type to tell the compiler "Please allow this closure to escape". If we remove #escaping:
class A {
var closure: (() -> Void)?
func someMethod(closure: () -> Void) {
}
}
and try to write self.closure = closure, it doesn't compile!
I am going in a more simpler way.
Consider this example:
func testFunctionWithNonescapingClosure(closure:() -> Void) {
closure()
}
The above is a non-escaping closure because the closure is
invoked before the method returns.
Consider the same example with an asynchoronous operation:
func testFunctionWithEscapingClosure(closure:#escaping () -> Void) {
DispatchQueue.main.async {
closure()
}
}
The above example contains an escaping closure because the closure invocation may happen after the function returns due to the asynchronous operation.
var completionHandlers: [() -> Void] = []
func testFunctionWithEscapingClosure(closure: #escaping () -> Void) {
completionHandlers.append(closure)
}
In the above case you can easily realize the closure is moving outside
body of the function so it needs to be an escaping closure.
Escaping and non escaping closure were added for compiler optimization in Swift 3. You can search for the advantages of nonescaping closure.
I find this website very helpful on that matter
Simple explanation would be:
If a closure is passed as an argument to a function and it is invoked
after the function returns, the closure is escaping.
Read more at the link I passed above! :)
By default the closures are non escaping. For simple understanding you can consider non_escaping closures as local closure(just like local variables) and escaping as global closure (just like global variables). It means once we come out from the method body the scope of the non_escaping closure is lost. But in the case of escaping closure, the memory retained the closure int the memory.
***Simply we use escaping closure when we call the closure inside any async task in the method, or method returns before calling the closure.
Non_escaping closure: -
func add(num1: Int, num2: Int, completion: ((Int) -> (Void))) -> Int {
DispatchQueue.global(qos: .background).async {
print("Background")
completion(num1 + num2) // Error: Closure use of non-escaping parameter 'completion' may allow it to escape
}
return num1
}
override func viewDidLoad() {
super.viewDidLoad()
let ans = add(num1: 12, num2: 22, completion: { (number) in
print("Inside Closure")
print(number)
})
print("Ans = \(ans)")
initialSetup()
}
Since it is non_escaping closure its scope will be lost once we come out the from the 'add' method. completion(num1 + num2) will never call.
Escaping closure:-
func add(num1: Int, num2: Int, completion: #escaping((Int) -> (Void))) -> Int {
DispatchQueue.global(qos: .background).async {
print("Background")
completion(num1 + num2)
}
return num1
}
Even if the method return (i.e., we come out of the method scope) the closure will be called.enter code here
Swift 4.1
From Language Reference: Attributes of The Swift Programming Language (Swift 4.1)
Apple explains the attribute escaping clearly.
Apply this attribute to a parameter’s type in a method or function declaration to indicate that the parameter’s value can be stored for later execution. This means that the value is allowed to outlive the lifetime of the call. Function type parameters with the escaping type attribute require explicit use of self. for properties or methods. For an example of how to use the escaping attribute, see Escaping Closures
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: #escaping () -> Void) {
completionHandlers.append(completionHandler)
}
The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with #escaping, you would get a compile-time error.
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write #escaping before the parameter’s type to indicate that the closure is allowed to escape.
Definition of Escape
Swift’s closures are reference types, which means if you point two variables at the same closure they share that closure – Swift just remembers that there are two things relying on it by incrementing its reference count.
When a closure gets passed into a function to be used, Swift needs to know whether that function will get used immediately or whether it will be saved for use later on. If it’s used immediately, the compiler can skip adding one to its reference count because the closure will be run straight away then forgotten about. But if it’s used later – or even might be used later – Swift needs to add one to its reference count so that it won’t accidentally be destroyed.
Quick Example
A good example of an escaping closure is a completion handler. It’s executed in the future, when a lengthy task completes, so it outlives the function it was created in. Another example is asynchronous programming: a closure that’s executed asynchronously always escapes its original context.
public func responseData(
queue: DispatchQueue? = nil,
completionHandler: #escaping (DataResponse<Data>) -> Void)
-> Self
{
...
Extra Information
For performance reasons, Swift assumes all closures are nonescaping closures, which means they will be used immediately inside the function and not stored, which in turn means Swift doesn’t touch the reference count. If this isn’t the case – if you take any measure to store the closure – then Swift will force you to mark it as #escaping so that the reference count must be changed.
non-escaping(#noescape) vs escaping(#escaping) closure
[Function and closure]
non-escaping closure
#noescape is a closure which is passed into a function and which is called before the function returns
A good example of non-escaping closure is Array sort function - sorted(by: (Element, Element) -> Bool). This closure is called during executing a sort calculations.
History: #noescape was introduced in Swift 2 -> was deprecated in Swift 3 where became a default that is why you should mark #escaping attribute explicitly.
func foo(_ nonEscapingClosure: () -> Void) {
nonEscapingClosure()
}
escaping closure
escaping closure(reference) is alive when method was finished.
//If you have next error
Escaping closure captures non-escaping parameter
//`#escaping` to the rescue
#escaping is a closure which is
passed into a function
The owner function saves this closure in a property
closure is called(using property) after the owner function returns(async)
A good example of an escaping closure is a completion handler in asynchronous operation. If you do not mark you function with #escaping in this case you get compile time error. Reference to property in an escaping closure requires you to use self explicitly
class MyClass {
var completionHandler: (() -> Void)?
func foo(_ escapingClosure: #escaping () -> Void) {
//if you don't mark as #escaping you get
//Assigning non-escaping parameter 'escapingClosure' to an #escaping closure
completionHandler = escapingClosure //<- error here
}
func onEvent() {
completionHandler?()
}
}
completion is a completionHandlerAbout, if you want to highlight that it is #escaping you can use completionHandler naming
func foo(completion: () -> Void) {
//
}
func foo(completionHandler: #escaping () -> Void) {
//
}
[Sync vs Async]
[Java functional interfaces]
Here simple example of escaping and no escaping closures.
Non-Scaping Closures
class NonEscapingClosure {
func performAddition() {
print("Process3")
addition(10, 10) { result in
print("Process4")
print(result)
}
print("Process5")
}
func addition(_ a: Int, _ b: Int, completion: (_ result: Int) -> Void) {
print("Process1")
completion(a + b)
print("Process2")
}}
Creating an instance and calling function calling
let instance = NonEscapingClosure()
instance.performAddition()
Output:
Process3
Process1
Process4
20
Process2
Process5
And Escaping Closures
class EscapingClosure {
func performAddition() {
print("Process4")
addition(10, 10) { result in
print(result)
}
print("Process5")
}
func addition(_ a: Int, _ b: Int, completion: #escaping (_ result: Int) -> Void) {
print("Process1")
let add = a + b
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print("Process2")
completion(add)
}
print("Process3")
}}
Creating an instance and function calling
let instance = EscapingClosure()
instance.performAddition()
Output
Process4
Process1
Process3
Process5
Process2
20