Trouble with non-escaping closures in Swift 3 - swift

I have an extension Array in the form of:
extension Array
{
private func someFunction(someClosure: (() -> Int)?)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
But I'm getting the error: Passing non-escaping parameter 'someOtherClosure' to function expecting an #escaping closure.
Both closures are indeed non-escaping (by default), and explicitly adding #noescape to someFunction yields a warning indicating that this is the default in Swift 3.1.
Any idea why I'm getting this error?
-- UPDATE --
Screenshot attached:

Optional closures are always escaping.
Why is that? That's because the optional (which is an enum) wraps the closure and internally saves it.
There is an excellent article about the quirks of #escaping here.

As already said, Optional closures are escaping. An addition though:
Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.
Can be used like this:
extension Array {
private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}
func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}
let x = [1, 2, 3]
x.someOtherFunction(someOtherClosure: { return 1 })
Hope this is helpful!

The problem is that optionals (in this case (()-> Int)?) are an Enum which capture their value. If that value is a function, it must be used with #escaping because it is indeed captured by the optional.
In your case it gets tricky because the closure captured by the optional automatically captures another closure. So someOtherClosure has to be marked #escaping as well.
You can test the following code in a playground to confirm this:
extension Array
{
private func someFunction(someClosure: () -> Int)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
let f: ()->Int = { return 42 }
[].someOtherFunction(someOtherClosure: f)

Related

How can I change an inout parameter from within a escaping closure?

I was trying to modify a parameter of function from within a escaping closure as below:
var completion = [()->Void]()
func addCompletion(closure: #escaping ()->Void) {
completion.append(closure)
}
func testAdd(v: inout Int) {
addCompletion{
v = 1 // Compiler tells 'Escaping closure captures 'inout' parameter 'v'
print("hello1 \(v)")
}
}
var x = 0
testAdd(v:&x)
for comp in completion {
comp()
}
I was wondering if there is another way to let escaping closure change surrounding variable (as function's inout parameter), besides making it into reference type as a class object.
inout is specified to have a "copy-in copy-out" behaviour. The value of x is copied when you call the function. In the function body, the copy of x can be modified, or whatever. Then, when the function returns, the copy is copied again, and assigned to the original x. "Call-by-reference" could happen as an optimisation.
This explains why you can't modify an inout parameter in an escaping closure. The swift compiler can't possibly know when every escaping closure returns, to copy the modified value back.
You can use an actual pointer:
func testAdd(v: UnsafeMutablePointer<Int>) {
addCompletion{
v.pointee = 1 // you just need to change all references to "v" to "v.pointee"
print("hello1 \(v.pointee)")
}
}
Alternatively, if you don't like pointers, you can also do this trick (adapted from my other answer):
func testAdd(modifyV: #escaping ((inout Int) -> Void) -> Void) {
addCompletion{
modifyV { v in // here you can change v however you like!
v = 1
print("hello1 \(v)")
}
}
}
You just need to change the caller to:
testAdd { $0(&x) }

What is the meaning of var something: (() -> Void)? in Swift [duplicate]

I'm trying to declare an argument in Swift that takes an optional closure. The function I have declared looks like this:
class Promise {
func then(onFulfilled: ()->(), onReject: ()->()?){
if let callableRjector = onReject {
// do stuff!
}
}
}
But Swift complains that "Bound value in a conditional must be an Optional type" where the "if let" is declared.
You should enclose the optional closure in parentheses. This will properly scope the ? operator.
func then(onFulfilled: ()->(), onReject: (()->())?){
if let callableRjector = onReject {
// do stuff!
}
}
To make the code even shorter we can use nil as default value for onReject parameter and optional chaining ?() when calling it:
func then(onFulfilled: ()->(), onReject: (()->())? = nil) {
onReject?()
}
This way we can omit onReject parameter when we call then function.
then({ /* on fulfilled */ })
We can also use trailing closure syntax to pass onReject parameter into then function:
then({ /* on fulfilled */ }) {
// ... on reject
}
Here is a blog post about it.
Since I assume, that this "optional" closure should simply do nothing, you could use a parameter with an empty closure as default value:
func then(onFulfilled: ()->(), onReject: ()->() = {}){
// now you can call your closures
onFulfilled()
onReject()
}
this function can now be called with or without the onReject callback
then({ ... })
then({ ... }, onReject: { ... })
No need for Swift's awesome Optionals? here!
Maybe it's a cleaner way. Specially when the closure has complicated parameters.
typealias SimpleCallBack = () -> ()
class Promise {
func then(onFulfilled: SimpleCallBack, onReject: SimpleCallBack?){
if let callableRjector = onReject {
// do stuff!
}
}
}
As an alternative to creating a TypeAlias or using well-placed parentheses, there's always Swift's Optional type itself.
It can be used just like your typical Java (or in this case Swift) Generic Array syntax Optional<() -> ()>
OR in context:
func callAClosure(firstClosure: () -> (), secondClosure: Optional<() -> ()> {
if let secondClosure = secondClosure {
secondClosure()
}
else { firstClosure() }
}
I find this to be fairly clean. As a bonus, in the context of SwiftUI where generics can be common, like struct CommonList<T: View>: View then you don't have to create a typealias that only gets used once (commonly the init function for that struct). Instead, you make one simple optional closure parameter, and you're all done!
Hopefully this helps anyone that runs into the issue and happy coding!

Swift optional escaping closure

Compiler error Closure use of non-escaping parameter 'completion' may allow it to escape, Which make sense because it will be called after the function return.
func sync(completion:(()->())) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion()
}
}
But if I make closure optional then no compiler error, Why is that? closure can still be called after the function returns.
func sync(completion:(()->())?) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion?()
}
}
Wrapping a closure in an Optional automatically marks it escaping. It's technically already "escaped" by being embedded into an enum (the Optional).
Clarification:
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
error: assigning non-escaping
parameter 'handlerParameter' to an #escaping closure
let chObject = CompletionHandler.handler = handlerParameter
with a note that:
note: parameter 'handlerParameter' is implicitly non-escaping func
doSomething(handlerParameter: completion) {
Why is that? the assumption is that the code snippet has nothing to do with the #escaping...
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.
As a reference, there are bugs reported related to this issue:
Optional closure type is always considered #escaping.
#escaping failing on optional blocks.
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
First comment:
The actual issue here is that optional closures are implicitly
#escaping right now.
Second comment:
That is unfortunately the case for Swift 3. Here are the semantics for
escaping in Swift 3:
1) Closures in function parameter position are
non-escaping by default
2) All other closures are escaping
Thus, all generic type argument closures, such as Array and Optional, are escaping.
Obviously, Optional is enum.
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
Class Case:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
Struct Case:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
The two above code snippets would leads to the same output (compile-time error).
For fixing the case, you would need to let the function signature to be:
func doSomething( handlerParameter: #escaping completion)
Back to the Main Question:
Since you are expecting that you have to let the completion:(()->())? to be escaped, that would automatically done -as described above-.

swift repeat func: expected identifier in function declaration

I'm using a Swift learning book about extensions with a closure as a parameter.
In the book, it told me
extension Int {
func repeat(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}
On the line
func repeat(work: () -> ()) {
Xcode tells me
Expected identifier in function declaration
and on the line:
for _ in 0..< self {
Xcode tells me
Braced block of statements is an unused closure
and
Expected ‘{’ to start the body of for-each loop
Can anyone can tell me why these errors occur and what should I do?
There are a number of problems with the posted code:
extensionInt should be extension Int, although I suspect this is a typo in you post
As #Zhao Yi pointed out, repeat is a Swift keyword, you need to rename your function (e.g. repeatWork)
The Swift Half-Open Range Operator requires either an empty space on both sides, or no space on both sides. Both these are valid:
0 ..< self
0..<self
Finally, you can call this function like this:
2.repeatWork({
print("Hello")
})
or this:
2.repeatWork {
print("Hola")
}
repeat is a keyword you can't use as a function name. Rename it to something else:
extension Int {
func repeat1(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}

parameters with optional closures in swift

I'm using optional closures, but can't find a way to pass on a parameter.
Searched everywhere, tried all suggestions, but can't get it to work.
My code:
func DoAlert(title: String
, message: String
, actions: String
, sender: AnyObject?
, Ctlr : UIViewController
, SegueString: String?
, YesClosure: ()->() = {}
, NoClosure: ()->() = {}
, StartClosure: ()->() = {}
, EndClosure: ()->() = {}
) {
if (actions.rangeOfString("Ok") != nil {
alert.addAction(UIAlertAction(title: "OK", style: .Default ) { action -> Void in
EndClosure()
})}
} // end function
I want to add a closure for Ok, where the 'self' parameter is needed.
Something like below:
// add to func doAlert:
, OkClosure: (AnyObject)->() = {}
// add to action Ok (before the EndClosure:
OkClosure(sender!)
Getting error on first line:
AnyObject is not subtype of ()
If I leave AnyObject out of first line, Getting error:
Cannot convert the expression's type 'AnyObject' to type '() => ()'
All other trials give me similar 'Tuple' errors.
How do I code the passing of parameters in the optional closures in my code?
Firstly, to use closures as an argument for a function, you should declare them like so:
func myFunc(closure: (Int) -> Void) {
// Now I can call closure like so:
let myInt = 10
closure(myInt)
}
(As pointed out by #Airspeed Velocity, the parenthesis around Int are not strictly required because there is only one argument. Whether you include them is just personal preference)
Secondly, you can modify the previous function to include an optional closure, as follows:
(Note the ? and parenthesis around the closure that indicate the closure is an optional, not the return type)
func myFunc(closure: ((Int) -> Void)?) {
// Now when calling the closure you need to make sure it's not nil.
// For example:
closure?(10)
}
Thirdly, to add a default value of nil, which is what it looks like you're trying to do with the = {} on the end of YesClosure: ()->() = {}, you could do:
func myFunc(closure: ((Int) -> Void)? = nil) {
// Still need to make sure it's not nil.
if let c = closure {
c(10)
}
}
Finally, just as a note, you can set the names of the arguments of the closure, which can make it easier to identify what you're passing to the closure when calling it. For example:
(Note - here parenthesis are required around value: Int)
func myFunc(closure: ((value: Int) -> Void)) {
closure(value: 10)
}
Even more finally, you could use typealias. According to the documentation:
A type alias declaration introduces a named alias of an existing type into your program.
Here's an example of how to use it with a closure:
typealias MyClosureType = () -> Void
func myFunc(closure: MyClosureType) {
closure()
}
Hope that helps!
I think I found it. I can't use parameters in the closure when I call func. In func itself I need to define the parameters used (closure: (sender: AnyObject) -> Void), make sure the variables are defined (or provided as a separate parameter) and add them to the closure call.
#IBAction func buttonPressed(sender: AnyObject) {
myFunc (sender, doClosure)
}
func myFunc(sender: AnyObject, closure: (sender: AnyObject) -> Void) {
// Now I can call closure like so:
closure (sender: sender)
}
func doClosure(sender: AnyObject) {
println("sender = \(sender)")
}