swift repeat func: expected identifier in function declaration - swift

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

Related

Function in capture list: "extraneous argument label" error

func customPrint(number: Int, via printingFunction: #escaping (Int) -> Void) {
printingFunction(number)
}
class Temp {
func tempPrintingFunction(number i: Int) {
print(i)
}
func print5() {
customPrint(number: 5) { [self] number in
tempPrintingFunction(number: number)
}
}
}
Temp().print5()
This code is fine: compiles and works as expected.
But when I pass function itself in capture list instead of self:
func print5() {
customPrint(number: 5) { [tempPrintingFunction] number in
tempPrintingFunction(number: number)
}
}
I get the error:
Extraneous argument label 'number:' in call
When I remove the label, everything backs to normal.
But it's weird. What is it? Bug or feature? I can't find any information about this neither in documentation nor on forums.
Bonus question:
Why doesn't the code crash, when I pass unowned self to the capture list? Shouldn't it crash? I want it to crash 🙂
Edited:
By the way, is there any difference in this situation between capturing self and function itself? In terms of retain cycles, etc. If we capture function, self will be captured as well, isn't it?

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

Trouble with non-escaping closures in Swift 3

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)

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.

Swift issue in Swift for Beginners Chapter 6

This line of code from "Swift for Beginners" won't work on the latest Swift Version. I'm guessing the repeat keyword can no longer be used as is in the code, so if I change it to repeato, the code loops 5 times as expected but only shows "()" in the console, without the actual String. How can this be fixed?
here is the simple code:
// extension with a closure as a parameter
extension Int {
func repeat(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}
5.repeat({
println("repeat this string")
})
Changes in Swift 2:
repeat is now a keyword
println is now print
This should work:
extension Int {
func times(work: () -> Void) {
for _ in 0..<self {
work()
}
}
}
5.times {
print("repeat this string")
}