Confused by the example code which adds new instance methods to types - swift

The following code snippet is copied from the official document where it is used to demonstrate how to use the Extensions to add method to existing types.
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()//what's going on here?
}
}
}
3.repetitions { //why I don't have to call as `repetitions()`
print("Hello!")
}
Question: The question is not asking how the extinsion extens. I just feel a bit confused about this code, why it looks like so? why use task() inside function body? Where it comes from? for the line 3.repetition why not write it as 3.repetition()
Thanks a lot

repetitions is a function that accepts as its parameter a function and calls that function several times.
To call repetitions, we could say (note, this is Swift 3):
func sayHi() {
print("Hello")
}
3.repetitions(task:sayHi)
But why define an extra name sayHi? Instead we use an anonymous function:
3.repetitions(task:{print("Hello"})
But in that case we are allowed to omit the parenthesis in this call to repetitions and use trailing syntax:
3.repetitions{print("Hello")}

Why use task() inside function body?
The task parameter is defined as a closure aka an anonymous function:
task: () -> Void
This says that the function expects another function as a parameter, one which takes no arguments and returns no values.
Calling task() invokes that function which is passed in.
for the line 3.repetition why not write it as 3.repetition()
Search for "Trailing Closure Syntax". If the last argument to a Swift function is a closure, you can attach it to the call outside of the () argument list.
Or in other words, this is exactly the same:
3.repetitions(task: {
print("Hello!")
})
(whether you have to use task: as the keyword argument depends on whether you use Swift 2 or 3.

Related

Unable to run function with arguments in Swift

I've been trying to create a menu item for my application in swift, and by pressing different buttons on the menu I want to run different python scripts. I'm very new to Swift, and I'm guessing there's a simple mechanic I'm just missing here.
The problem is now that I'm trying to create a button, with an action being run when it is pressed.
The function call is in a Toolbar, which is in itself in a NavigationView:
ToolbarItem {
Menu {
Button("Label", action: myFunc("My string"))
} label: {
Label("Scripts", systemImage: "applescript")
}
}
Where the function myFunc is like this:
func myFunc(_ param: String) -> Void {
print(param)
}
(The integer is just a placeholder for a later value which would correspond to the path of the script I'm trying to run)
The error is:
Cannot convert value of type 'Void' to expected argument type '() -> Void'
The weird thing is that when I exclude the argument in the function call, like calling a:
func myFunc() {
print("Hello")
}
From the same location, it works just fine. Is there a limitation to the buttons like not being able to send arguments to their functions?
I've looked at different solutions, but they all seem way too complicated for this error. I saw one guide where it was because of an empty view, but this doesn't seem to be the error at hand.
The amount of buttons will later be in a ForEach. I'm however a bit conflicted regarding what the best way of storing the paths for the scripts is. I've been thinking about doing an enum with the different paths as rawValues. But I'd like different labels for the buttons than the actual paths of the files, so I'd need two values stored in the rawValues, is this possible? Like using a dictionary and using the name as key and the value as the path. Or do you have any inputs on a better way to solve this problem?
I'm very open for suggestions, the goal is just to be able to run scripts with buttons in a menu!
The problem is that you are executing the function myFunc by putting the parentheses after it, which will result in a Void value rather than a function of type () -> Void, which the Button initialiser expects.
You can fix this by wrapping your function call in a closure.
ToolbarItem {
Menu {
Button("Label", action: { myFunc("My string") })
} label: {
Label("Scripts", systemImage: "applescript")
}
}
This way you really are passing a closure of type () -> Void to the Button init (which it expects), which will only be executed on the button tap. With your previous implementation, the function was executed as soon as the Button is initialised rather than when it it tapped.
The action parameter of a Button view expects an argument of type () -> Void. This means that you need to pass a reference to a function/closure that takes no arguments and returns nothing.
That's why, when you removed the argument from myFunc (resulting in this button code:
Button("Label", action: myFunc)
it worked, because it's not calling myFunc, but simply referencing it. If you want to call myFunc with an argument, you can wrap it in a closure, like so:
Button("Label", action: { myFunc("My string") })
In this way, the closure takes no arguments and returns nothing, matching the required type.

Swift - Ambiguous reference to member '==' error

I've done some searching and can't seem to find a solution for my below issue. I'm fairly new to swift so working through some issues. I have the below function which is just a stub containing the signature of the function and a return value just to get it to compile.
The test code is what I've been given, I did not write this and unfortunately cannot alter it.
My issues is that when I run it, it says that the test that calls this function has an "Ambiguous call to member '=='". I cannot alter the test code. Whatever the issue is must be in my function signature i'm assuming but could use some help.
Function That I am writing (That I assume contains the issue):
func contains(target: StringOrInt, compare: Character ) -> Bool {
return false
} // contains
Test that calls the function (I'm not allowed to edit this and did not write it):
func test_contains_cons_2_strings_3() {
let list1 = MyList.cons("foo", MyList.cons("bar", MyList.empty))
assertEquals(testName: "test_contains_cons_2_strings_3",
expected: true,
received: list1.contains(target: "bar", compare: ==))//Error is on this line '=='
} // test_contains_cons_2_strings_3
Error:
main.swift:807:67: error: ambiguous reference to member '=='
received: list1.contains(target: "foo", compare: ==))
Also note that "StringOrInt" is a protocol that I've defined that acts as an extension on both Int and String. This is done because the test code (Which i did not write and cannot edit) passes both strings and ints to this same variable and function.
Thanks advance for any help, I really appreciate it!
I think you want to compare two strings by passing "==" operator and return a Boolean value.If so you can use the below method,
func myList(_ compare:((String, String) -> Bool)) -> Bool {
return compare("foo","bar")
}
myList(==)
I was able to figure this out using the below. I implemented an enum of generic type and the nan extension on that enum. I then used this generic type within the contains function to represent multiple types instead of StringOrInt. Thanks everyone for the comments and the help.
enum implemented:
indirect enum my_list<A> {
case cons(A, my_list<A>)
case empty
}
I then implemented in extension for this enum "extension my_list" and placed the contains function within the extension.
contains function signature/stub:
func contains(target: A, compare:((A, A) -> Bool))
-> Bool {
return true
}// contains

What does () mean in Swift?

I have the following function in Swift 3
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
{
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
}
}
What does _ completionHandler argument in fetchOrders mean?
What does (orders: () throws -> [Order]) mean?
PS : I am new to iOS and Swift
There's quite a lot in here, so we'll break it down one piece at a time:
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
This is a function called fetchOrders.
It has one parameter (completionHandler) and returns nothing.
The first _ indicates that there is no "external name" of the first parameter. That is, you do not have to label it (in fact, you cannot). (For subtle reasons that don't really matter here, I believe the author made a mistake using _ there, and I would not have done that.)
The completionHandler is the "internal name," what the parameter is called inside the function.
The type of completionHandler is (_ orders: [Order]) -> Void. We'll break that down now.
This value is a closure that takes an [Order] (array of Order) and returns Void. Informally this means "returns nothing" but literally means it returns the empty tuple ().
The _ orders: syntax is in practice a comment. In principle the _ is an external name (but that's the only legal external name for a closure), and orders is an internal name, but in reality, closures parameters do not have names in any meaningful way, so this is purely informational.
I believe this is a poor use of the closure parameter commenting system. Since orders tells us nothing more than [Order], I would have omitted it, and made the type just ([Order]) -> Void.
Now we'll turn to the next line:
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
This calls the fetchOrders method on ordersStore. We can tell from this code that fetchOrders takes a closure parameter. This is called "trailing closure" syntax in Swift, and is why I would not have used the _ for our closure. With trailing closure syntax, the external name of the parameter is not needed.
The author has provided type information here that probably wasn't necessary, but we can explore it anyway. This could likely have been written as just { orders in, but then the reader would probably have been surprised by this somewhat unusual code.
We have been passed a closure called orders that takes nothing and returns [Order] or throws an error. Basically this is a way to say that fetchOrders might fail.
The author is working around an awkwardness in Swift's throws system, which does not have a natural way to express an asynchronous action that might fail. This is one way to fix it; you pass a throwing (i.e. a possibly failing) function. I don't favor this approach, I favor using a Result enum for this case because I think it scales better and avoids possible unintended side effects, but that's a debatable point (and the Swift community hasn't really decided how to deal with this common problem).
This all leads us to:
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
This is where the orders closure is evaluated. (This is very important; if orders has side effects, this is when they occur, which may be on a different queue than was intended. That's one reason I don't favor this pattern.) If the closure succeeds, we return its result, otherwise we return [] in the catch below.
In this particular case, the throws approach is slightly silly, because it's silently flattened into [] without even a log message. If we don't care about the errors, then failure should have just returned [] to start with and not messed with throws. But it's possible that other callers do check the errors.
In either case, we call the completionHandler closure with our result, chaining this back to our original caller.
This do/catch block could have been more simply written as:
let completedOrders = try? orders() ?? []
completionHandler(completedOrders)
This makes it clearer that we're ignoring errors by turning it into an optional, and avoids code duplication of the call to completionHandler.
(I just add the extra let binding to make the code a little easier to read; it isn't needed.)
The completionHandler argument means that the expected parameter (named completionHandler) must be a function that takes a list of Order objects and does not return any value.
completionHandler is the a variable name. In this specific example, this variable is a callback. You know is a callback function because (orders: [Order]) -> Void is it's data type; in this particular case, said data type is a function that receives an array of Order objects in a variable _orders and doesn't have a return value (the Void part).
TL;DR:
it's the variable name, of type:
function which receives an array of Order as a parameter and acts as a callback.

What does this syntax mean in Swift?

I am new to Swift and am confused with this type of syntax. I know when you add () to the end of something you initialize it. I am still confused what this means though! I am adding code below.
Please help clarify what parenthesis at the end of this means! Thank you!
Also what does it mean to have all that code after the equal sign in this case? ( I know how to create a variable and add a String,Int or something like that to it).
I am just confused a bit wth this code.
Thanks for being understanding to a beginner!
var viewController: ViewController = {
return self.instantiateViewControllerWithIdentifier("Play") as ViewController
}()
EDIT 1 -
var statusBarStyle: UIStatusBarStyle = .Default {
didSet{
setNeedsStatusBarAppearanceUpdate()
}
}
{} declares a closure, which is anonymous function. Everything between { and } is a function body. Since closure defined in provided code does not have arguments it can be executed as regular function by (). { .. }() is just defining and immediately executing of anonymous function.
In a body of a function there is a call of instantiateViewControllerWithIdentifier("Play") which returns AnyObject. As viewController variable (var) expected to ba a type of ViewController, we cast AnyObject result of instantiateViewControllerWithIdentifier as ViewController
As for statusBarStyle, UIStatusBarStyle is an enum. .Default is one of enum's cases. It can be written alternatively as var statusBarStyle = UIStatusBarStyle.Default. The code that goes in the { ... } is a way to declare getter and setter behavior. In this particular case there is only one behavior didSet defined, which means as soon as value of UIStatusBarStyle updated (which is possible, as it is var), call function setNeedsStatusBarAppearanceUpdate. There are other getters & setters keywords that you may read about in Swift Book — https://itunes.apple.com/us/book/swift-programming-language/id881256329 such as get, set, willSet.
As Nikita said its instantly calling the anonymous function you declared. This is really useful as it allows you to add logic when initialising a var or let.
Since the function takes no arguments, it makes it harder to see at first that it actually is a function. An example with an argument makes this concept a lot clearer.
let oneMore: Int = { (num: Int) in num + 1 }(5) //oneMore = 6
We are creating a function that takes one Int argument num and implicitly returns an Int (the compiler knows this because of the type annotation on oneMore. By following the closure with (5) we are calling the anonymous function with the value of 5.
Hopefully this example makes it more clear what happening. Note for an anonymous function in the context we would never need to provide argument since it will only ever be called once with the arguments following it, so we can just include the argument within the function body.
let oneMore: Int = { 5 + 1 }()
In the second example the braces are allowing you to include property observers to the variable. an example of a property observer is didSet which is called each time after you assign a value to the variable. more info can be found in apples docs here.

Method parameters in nested closure

I am trying to understand how parameters passed to a method are available to nested closures. I'm nervous that something I wrote won't always have the original parameters available.
(these are drastically simplified examples)
I have a method that I wrote that specifies a closure as a parameter:
func saveNameAndAgeToServer(serverParams: [String:String], completionHandler: (age: NSNumber) -> ()) {
// Connect to a server
// POST a name and dob from serverParams
// Receives a current age in completion:
completionHandler(age: 22)
}
Now somewhere else I create another method, that also specifies a closure, takes two parameters and calls the first function:
func AwesomeFunc(name: String, dob: NSDate, completionHandler: (isOverTwentyOne: Bool) -> ()) {
let formattedDob = NSDateFormatter().stringFromDate(dob)
saveNameAndAgeToServer([name:formattedDob]) { (age) -> () in
if (age as Int) >= 21 {
print("\(name) can have a beer.")
completionHandler(isOverTwentyOne: true)
} else {
print("\(name) is too young to drink, he can have a water.")
completionHandler(isOverTwentyOne: false)
}
}
}
Am I able to guarantee that the parameters (name and dob) passed into this latter function will always be available?
What I'm trying to ask is will the memory that the saveNameAndAgeToServer closure runs within always have the parameters of AwesomeFunc available to it? I'm pretty sure the function is all being held while whatever it calls is completed but would love a 2nd opinion.
You are correct, captured variables will last for the life of the closure. Here's an exert on capturing variables from apple's swift documentation:
A closure can capture constants and variables from the surrounding
context in which it is defined. The closure can then refer to and
modify the values of those constants and variables from within its
body, even if the original scope that defined the constants and
variables no longer exists.
In Swift, the simplest form of a closure that can capture values is a
nested function, written within the body of another function. A nested
function can capture any of its outer function’s arguments and can
also capture any constants and variables defined within the outer
function.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html