iOS Swift 3 parameters have underscore in front - ios

Today I opened my project in Xcode and it required to convert current Swift to Swift 3. After the conversion, I found all parameters of functions have an underscore in front. For example, func didGetWeather(_ weather: Weather) {}. I tried to take away the underscores and it worked fine. I wonder what those underscores are for.

Before swift3 the label of the first parameter by default was not listed in the function call, in swift3 does, the way to not name the parameters is placing an underscore before the parameter name in the signature, swift3 migrator add underscore the functions first parameter to not break existing code that rely on not placing the first label at function call.

As per Apple documentation:
If you don’t want an argument label for a parameter, write an underscore (_) instead of an explicit argument label for that parameter.
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)
If a parameter has an argument label, the argument must be labeled when you call the function.
In Swift 2, we used to declare functions like:
func myFunc(param1 param:String) {}
and we had to call it like:
myFunc(param1:)
But later Apple introduced a way to omit argument labels using underscore(_), the function declaration would be:
func myFunc(_ param:String) {}
And then we can call the function in two ways:
myFunc(_:) // when we don't want to pass any parameters
Or
myFunc(param:"some string") // when we want to pass any parameters
The first way (using _) is mostly used when we want to define a selector. For eg:
someButton.addTarget(self, action: #selector(shareCatalog(_:)), for: .touchUpInside)

Yes, its changelog in Swift 3.0.
All function parameters have labels and "_" with at first of function :
Now below all default methods also have (_).
override func viewWillAppear(_ animated: Bool)
override func didMoveToView(_ view: SKView)
func textFieldShouldReturn(_ textField: UITextField) -> Bool

Related

Xcode requests I use argument label when none defined in function?

I have this protocol which I go on to implement in my view controller.
protocol GuessDelegate {
func userDidFinish(_controller:GuessInputViewController, guess:String)
}
However, when I call it, the compiler forces me to type _controller: just before self (please see below). It doesn't allow me to write delegate.userDidFinish(self, guess: guessText) and complains about a missing argument label if I try that.
However, the method signature has no argument label, just a parameter name controller with a leading underscore which I thought meant the parameter name therefore doesn't need to be typed out in the call to the function.
What is going on exactly? Is it perhaps behaving like this because it's a protocol method?
#IBAction func saveGuess(_ sender: AnyObject) {
if let delegate = delegate, let guessText = guessTextField.text {
delegate.userDidFinish(_controller: self, guess: guessText)
}
}
put a space between underscore and controller
protocol GuessDelegate {
func userDidFinish(_ controller:GuessInputViewController, guess:String)
}

Why is the #objc tag needed to use a selector?

I am trying to use a selector to see if a certain protocol can perform an action. When I try it like this:
protocol Test {
func hello()
func goodBye(a: String)
}
class Tester: NSObject, Test {
override init() {}
func hello() { }
func goodBye(a: String) { }
}
let a: Test = Tester()
let result = a.responds(to: Selector("goodByeWithA:"))
In this case, result evaluates to false.
But if I add the #objc tag to the protocol, it evaluates as true.
#objc protocol Test {
func hello()
func goodBye(a: String)
}
Why is this?
On a side note, I know that it is now recommended to use the #selector syntax and to move away from using strings, but for various reasons, I have to use a string in this case.
EDIT: This only started happening once I migrated my project to Swift 4.2
By default Swift generates code that is only available to other Swift code, but if you need to interact with the Objective-C runtime – all of UIKit, for example – you need to tell Swift what to do.
That’s where the #objc attribute comes in: when you apply it to a class or method it instructs Swift to make those things available to Objective-C as well as Swift code. So, any time you want to call a method from a UIBarButtonItem or a Timer, you’ll need to mark that method using #objc so it’s exposed – both of those, and many others, are Objective-C code.
Don’t worry: if you forget to add #objc when it’s needed, your code simply won’t compile – it’s not something you can forget by accident and introduce a bug.

What is the difference between didMove(to view: SKView) and didMoveToView(view: SKView)?

As in the title, what is the difference between didMove(to view: SKView) and didMoveToView(view: SKView)?
I understand that didMoveToView is the method and that view is of type SKView in the older(?) version. I don't understand the deal with 'to view: SKView' being passed to the didMove method. Are 'to' and 'view' separate variables? Is 'to' part of 'didMove'? What is going on?
EDIT: I understand that they both accomplish the same thing - but why is 'to' in the area that parameters normally go? Is there a benefit to this? It seems to be unnecessary complication?
The difference is only in the syntax.
The new Swift 3 syntax is didMove(to view: SKView)
In Swift:
Each function parameter has both an argument label and a parameter
name.The argument label is used when calling the function; each
argument is written in the function call with its argument label
before it. The parameter name is used in the implementation of the
function. By default, parameters use their parameter name as their
argument label.
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
So , the to in the swift 3 version is only the argument label.
Probably you have also seen function where there is no need to insert the parameterName.
If you don’t want an argument label for a parameter, write an underscore (_) instead of an explicit argument label for that parameter.
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
// In the function body, firstParameterName and secondParameterName
// refer to the argument values for the first and second parameters.
}
someFunction(1, secondParameterName: 2)
Hope it helps to better understand these modifications: you can find more details here
Nothing!
didMove(to view: SKView) is Swift 3 syntax.
didMoveToView(view: SKView) is Swift 2.x syntax.
FYI many many other parameters and method namings changed from Swift 2 to Swift 3. A very good list of changes can be found here
usage
It's debated but to most people the Swift 3 syntax is more readable since you do didMove(to: xyzView) while the Swift 2.x syntax is less readable when you do didMoveToView(xyzView)

How to discriminate same method selector on Swift 3.0? [duplicate]

[NOTE This question was originally formulated under Swift 2.2. It has been revised for Swift 4, involving two important language changes: the first method parameter external is no longer automatically suppressed, and a selector must be explicitly exposed to Objective-C.]
Let's say I have these two methods in my class:
#objc func test() {}
#objc func test(_ sender:AnyObject?) {}
Now I want to use Swift 2.2's new #selector syntax to make a selector corresponding to the first of these methods, func test(). How do I do it? When I try this:
let selector = #selector(test) // error
... I get an error, "Ambiguous use of test()." But if I say this:
let selector = #selector(test(_:)) // ok, but...
... the error goes away, but I'm now referring to the wrong method, the one with a parameter. I want to refer to the one without any parameter. How do I do it?
[Note: the example is not artificial. NSObject has both Objective-C copy and copy: instance methods, Swift copy() and copy(sender:AnyObject?); so the problem can easily arise in real life.]
[NOTE This answer was originally formulated under Swift 2.2. It has been revised for Swift 4, involving two important language changes: the first method parameter external is no longer automatically suppressed, and a selector must be explicitly exposed to Objective-C.]
You can work around this problem by casting your function reference to the correct method signature:
let selector = #selector(test as () -> Void)
(However, in my opinion, you should not have to do this. I regard this situation as a bug, revealing that Swift's syntax for referring to functions is inadequate. I filed a bug report, but to no avail.)
Just to summarize the new #selector syntax:
The purpose of this syntax is to prevent the all-too-common runtime crashes (typically "unrecognized selector") that can arise when supplying a selector as a literal string. #selector() takes a function reference, and the compiler will check that the function really exists and will resolve the reference to an Objective-C selector for you. Thus, you can't readily make any mistake.
(EDIT: Okay, yes you can. You can be a complete lunkhead and set the target to an instance that doesn't implement the action message specified by the #selector. The compiler won't stop you and you'll crash just like in the good old days. Sigh...)
A function reference can appear in any of three forms:
The bare name of the function. This is sufficient if the function is unambiguous. Thus, for example:
#objc func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test)
}
There is only one test method, so this #selector refers to it even though it takes a parameter and the #selector doesn't mention the parameter. The resolved Objective-C selector, behind the scenes, will still correctly be "test:" (with the colon, indicating a parameter).
The name of the function along with the rest of its signature. For example:
func test() {}
func test(_ sender:AnyObject?) {}
func makeSelector() {
let selector = #selector(test(_:))
}
We have two test methods, so we need to differentiate; the notation test(_:) resolves to the second one, the one with a parameter.
The name of the function with or without the rest of its signature, plus a cast to show the types of the parameters. Thus:
#objc func test(_ integer:Int) {}
#nonobjc func test(_ string:String) {}
func makeSelector() {
let selector1 = #selector(test as (Int) -> Void)
// or:
let selector2 = #selector(test(_:) as (Int) -> Void)
}
Here, we have overloaded test(_:). The overloading cannot be exposed to Objective-C, because Objective-C doesn't permit overloading, so only one of them is exposed, and we can form a selector only for the one that is exposed, because selectors are an Objective-C feature. But we must still disambiguate as far as Swift is concerned, and the cast does that.
(It is this linguistic feature that is used — misused, in my opinion — as the basis of the answer above.)
Also, you might have to help Swift resolve the function reference by telling it what class the function is in:
If the class is the same as this one, or up the superclass chain from this one, no further resolution is usually needed (as shown in the examples above); optionally, you can say self, with dot-notation (e.g. #selector(self.test), and in some situations you might have to do so.
Otherwise, you use either a reference to an instance for which the method is implemented, with dot-notation, as in this real-life example (self.mp is an MPMusicPlayerController):
let pause = UIBarButtonItem(barButtonSystemItem: .pause,
target: self.mp, action: #selector(self.mp.pause))
...or you can use the name of the class, with dot-notation:
class ClassA : NSObject {
#objc func test() {}
}
class ClassB {
func makeSelector() {
let selector = #selector(ClassA.test)
}
}
(This seems a curious notation, because it looks like you're saying test is a class method rather than an instance method, but it will be correctly resolved to a selector nonetheless, which is all that matters.)
I want to add a missing disambiguation: accessing an instance method from outside the class.
class Foo {
#objc func test() {}
#objc func test(_ sender: AnyObject?) {}
}
From the class' perspective the full signature of the test() method is (Foo) -> () -> Void, which you will need to specify in order to get the Selector.
#selector(Foo.test as (Foo) -> () -> Void)
#selector(Foo.test(_:))
Alternatively you can refer to an instance's Selectors as shown in the original answer.
let foo = Foo()
#selector(foo.test as () -> Void)
#selector(foo.test(_:))
In my case (Xcode 11.3.1) the error was only when using lldb while debugging. When running it works properly.

what does "->" mean in swift when declaring functions?

example function
func example(titles: [String]) `->` [UIButton] {
}
and where could i find more docs on this topic (docs relevant to functions declaring in swift)?
There is no > in swift function declarations - someone botched up the HTML rendering in the page you were reading. It was supposed to be -> (an arrow made up of a hypen and the greater than operator) that's used to denote the return type of the function.
The text was supposed to read
func example(titles: [String]) -> [UIButton] {
}
Which means the example function has one parameter called titles of type [String] (array of String) and it returns a [UIButton] (array of UIButton).
Assuming you're talking about -> the portion after that denotes the return value of the function.

Resources