Unable to run function with arguments in Swift - 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.

Related

Trouble delaying function with variables passed to it in swift 4

I'm very new to swift and am having trouble with calling this function again on the 6th line after a delay, Xcode is telling me that
Argument of '#selector' does not refer to an '#objc' method, property, or initializer
I know what the problem is and have tried searching around but haven't been able to make anything work.
#objc func attemptToIdentify(_ user: String) {
if manager.status == .connected {
socket.emit("identify", user) //This functions correctly
} else {
print(manager.status, "... will attempt subscription in 1 second")
self.perform(#selector(attemptToIdentify(user)), with: nil, afterDelay: 1)
}
}
The problem is that attemptToIdentify(user) is a call. This is not the place for a call; you need a selector, i.e. the name of a function. So just put attemptToIdentify. If you need to pass something, you can pass it in the with parameter.
Even better, don't use perform:afterDelay: at all. If the idea is to add a delay to a call, just use asyncAfter (or my delay encapsulation of it).

Binder in RxSwift which accepts optional Any

I would like to create a Reactive extension to the UIButton which will take any object (value and reference type) and will enable the button based on the value. If it is nil I want to disable the button and enable if it there is value.
here is the code:
extension Reactive where Base: UIButton {
var isEnabledForModel: Binder<Any?> {
return Binder(base, binding: {
$0.isEnabled = $1 != nil
})
}
}
When I try to bind the observable which contains optional struct I get an error: Ambiguous reference to member 'bind(to: ). Is there any way to pass Any to the Binder or achieve it in different way? Maybe I want to make it too generic.
Yes, you are trying to make something that is too generic. For example, if you want the button disabled for a missing string, you probably also want it disabled for an empty string, but there is no way to express that in your binder.
That said, your code compiles fine for me. I suggest you clean your build folder and rebuild. Despite the fact that it compiles, the point of use becomes more complex than I think you would like.
let foo = Observable<Int?>.just(nil)
foo
.map { $0 as Any? }
.bind(to: button.rx.isEnabledForModel)
.disposed(by: bag)
Note that you have to manually map the Int? into a Any?. If you remove the map you will get an error "Generic parameter 'Self' could not be inferred". Because it's a generic parameter, the system won't look for possible matches through the inheritance tree and therefore won't accept the isEnabledForModel.

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

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.

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.

Difference between #warn_unqualified_access and #warn_unused_result?

Can anyone explain with one example of warn_unqualified_access and warn_unused_result
#warn_unused_result
Suppose you have an array representing a deck of cards:
var deck: [Card] = standardDeck.shuffled()
You want to write a function to deal a card to a player. You want to pull the “top” card from the deck, add it to the player's hand, and remove it from the deck:
func dealCard(to player: Player) {
guard let card = deck.last else { fatalError("Ran out of cards") }
player.hand.append(card)
deck.dropLast()
}
When you test your app, you are puzzled. All your players' hands are filled with copies of the same card.
Being new to Swift, you think dropLast modifies deck by removing its last element. Sadly, you are mistaken. It returns a new array containing all but the last element of deck. (Technically it returns an ArraySlice.)
The compiler and the standard library have conspired to help you figure out the problem. The dropLast function is annotated with #warn_unused_result, so Xcode shows you a warning on the dropLast call:
.../Cards.swift:85:10: Result of call to 'dropLast()' is unused
Seeing the warning, you decide to option-click on dropLast and read the documentation, which tells you what dropLast does (returns a new array), and you realize you need to change the line to this:
deck.removeLast()
Many, many functions, in the Swift standard library and in other libraries, are useful mainly for what they return. Ignoring the returned value of one of these functions is usually an error, so Swift makes it easy for the library author to warn the user about this behavior. In fact, Swift will probably soon be modified to apply #warn_unused_result by default, and to use a new #discardableResult attribute on the function to suppress the warning.
#warn_unqualified_access
You were so successful with your awesome card game on iOS that you've decided to port it to Mac OS X. On Mac OS X, you use NSView instead of UIView to show things on the screen. You're trying to figure out why your custom CardView is drawing itself incorrectly, so you want to call Swift's standard print function in drawRect:
class CardView: NSView {
var card: Card
override func drawRect(dirtyRect: NSRect) {
print("Drawing \(card)")
// drawing code here...
}
// rest of CardView here...
}
When you run your app, you're surprised to find that it pops up the print dialog! What's going on? The compiler and NSView have conspired to help you figure out the problem. The NSView.print function is annotated with #warn_unqualified_access, so Xcode shows you a warning on the print call:
.../CardView.swift:95:9: Use of 'print' treated as a reference to instance method in class 'NSView'
Seeing the warning, you option-click on print and read the documentation. You learn that NSView has its own print method, which lets the user print the contents of the view onto paper. How droll! Now you realize you need to change the call to explicitly use Swift's print function like this:
Swift.print("Drawing \(card)")
(It is virtually impossible to develop for Mac OS X in Swift without running into this particular case. Repeatedly.)
This sort of problem is much less common than the other problem of ignoring a function's result. NSView.print is the only case that I can recall running into.
Consider the following example:
class C {
#warn_unqualified_access func foo(x: Int) -> Int { return x }
#warn_unused_result func bar(x: Int) -> Int { return foo(x) }
}
func main() {
let c = C()
c.foo(1)
c.bar(1)
}
main()
This generates two warnings.
One in C.foo():
warning: use of 'foo' treated as a reference to instance method in class 'C'
use 'self.' to silence this warning
This is because I declared foo as #warn_unqualified_access, so it means the compiler wants me to explicitly refer to the object when accessing said member. This is because - for example - calling print in a subclass of NSView conflicts between Swift.print and NSView.print
The second warning is generated in main(), when calling bar:
warning: result of call to 'bar' is unused c.bar(1)
This is because I am calling bar(), declared as #warn_unused_result, and then discarding its result. This is useful, for example, in methods which return you a new value but have no side effects. If you choose to ignore the new value, you essentially wasted work. The compiler can warn you to point that out.