Can someone explain this Swift function to me? [duplicate] - ios

Example:
mutating func moveByX(deltaX: Double, y deltaY: Double)
The first parameter takes a Double and saves it in that method scope as deltaX. However, what are y and deltaY?
I read this and can't find anything about it: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html

This is how Swift mimics Objective C's named parameters (pseudo naming of arguments). Its pretty easy to break down.
mutating func moveByX(deltaX: Double, y deltaY: Double)
1 2 3 4 5 6
Beginning of method name
First parameter name
First parameter type
Second part of method name
Second parameter name
Second parameter type
In this example, the method is actually called moveByX:y: The equivalent Objective C method definition would look like this.
- (void)moveByX:(Double)deltaX y:(Double)deltaY
When calling this method, the second part of the name is included alone with the rest of the arguments.
var dub = Double(0.5)
moveByX(dub, y: dub)

In your example,
y is the external parameter name,
deltaY is the local parameter name, and
Double is the type of the parameter.
If you are familiar with Objective-C, this corresponds to a method with the following declaration:
-(void)moveByX:(double)deltaX y:(double)deltaY;

Methods in swift have both an external parameter name and a local parameter name. External is defined first then external, if only one is defined swift compiler puts in the defaults.
Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default.
In the example, "y" is the external parameter used when calling the method, "deltaY" is the variable name used in the internal calculations of that function.
You can also use _ to signify that you don't want a parameter to have an external name.
# is used for shorthand when both your external and internal name are the same.
Examples
1)
func exampleFunction(externalVarName1 localVarName1: Int, externalVarName2 localVarName2: Int) {}
is called like this:
exampleFunction(externalVarName1: 0, externalVarName2: 0)
2)
func exampleFunction2(autocompleteHintName: Int, autocompleteHintName2: Int) {}
is called like this
exampleFunction2(0, 0)
3)
func exampleFunction3(#nameForBoth: Int, #nameForBoth2: Int) {}
is called like this
exampleFunction3(nameForBoth: 0, nameForBoth2: 0)
4)
func exampleFunction4(nameForBoth nameForBoth: Int, nameForBoth2 nameForBoth2: Int) {}
is the same as 3) but throws a warning that the # shorthhand can be used. called like this
exampleFunction4(nameForBoth: 0, nameForBoth2: 0)
5)
func exampleFunction5(_: Int, _: Int) {}
is called like this
exampleFunction5(0, 0)

deltaX and deltaY are the parameter names when you are writing the function. However, when you call the function it will be called as movebyX(val, y: val) where val is replaced by the Double you are passing into the function. The y in the middle is essentially to help the readability of the function when it is called and is common practice in swift to make your code as readable as possible (the person calling your function can easily tell what each parameter is without looking at the function header).

Related

What does it mean if a mutating function setting it's self equals to another function

I was going through Apple's Arkit project sample. I was trying to understand the code since, I am still learning. I saw a function setting it self equals to another function can someone please explain what these functions are exactly doing. Please brief in detail.In the code the "mutating func normalize()" is setting it self to self.normalized why is it. What this code is doing. Can we not simply call "func normalized()" seems like we are re-creating the same function.
mutating func normalize() {
self = self.normalized()
}
func normalized() -> SCNVector3 {
if self.length() == 0 {
return self
}
return self / self.length()
}
func length() -> CGFloat {
return sqrt(self.x * self.x + self.y * self.y)
}
Values types in Swift can be mutable and immutable . So when you create struct( or any other value type) and assign it to variable (var) it is mutable and you call normalize() on it. It means that struct won’t be copied to another peace of memory and will be updated in place (will act like reference type). But when you assign it to constant (let) - it can’t be mutated so the only way to update values in this struct is to create new one with updated values as with normalized() method. Regarding your question - normalize() is just reusing logic for normalizing vector from normalized(). So this is completely fine solution. Assigning to self is only permitted in mutable methods. It’s basically rewrites value of struct with new one.
I'm assuming that this fragment is in a struct rather than a class.
self.normalized() makes a copy of self and divides the copy's components by its length and then returns the copy. self is not affected.
self.normalize() gets a normalised version of self and then replaces self by the copy. So it changes in place.
Under the hood, every member function passes self as an implicit argument. i.e. to the compiler the declaration looks like this:
func normalised(self: SCNVector3) -> SCNVector3
Putting mutating on the front of a function definition makes the hidden argument inout
func normalise(self: inout SCNVector3)
So, if you have
var a = SCNVector3(3, 4, 0)
let b = SCNVector3(4, 3, 0)
let c = b.normalized()
a.normalize()
After that code, c would be (0.8, 0.6, 0) and a would be (0.6, 0.8, 0). b would be unchanged.
Note that a has to be declared with var because it is changed in place by normalise()
Edit
In the comments khan asks:
What i am not able to understand is why do we have to create a func again we can use "func normalized"
The point being made is why can't we do something like this:
var a = SCNVector3(3, 4, 0)
a = a.normalized()
and not have the normalise() function at all?
The above will have exactly the same effect as a.normalize() and, in my opinion[1], is better style, being more "functional".
I think a.normalize() exists only because it is common in Swift to provide both forms of the function. For example, with sets you have both union() and formUnion(): the first returns the union of one set with another, the second replaces a set with the union of itself and another set. In some cases, the in place version of the function may be more efficient, but not, I think, with this normalize function.
Which you choose to use is a matter of your preference.
[1] Actually, the better style is
let a = SCNVector3(3, 4, 0).normalized()

iOS Swift 3 parameters have underscore in front

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

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.

Swift: syntax explanation - round brackets then "in"

I following tutorial and confused with following code:
let rectToDisplay = self.treasures.reduce(MKMapRectNull){
(mapRect: MKMapRect, treasure: Treasure) -> MKMapRect in
let treasurePointRect =
MKMapRect (origin: treasure.location.mapPoint, size: MKMapSize (width: 0, height: 0))
return MKMapRectUnion(mapRect, treasurePointRect)
}
In fact, I'm not understand only that line:
(mapRect: MKMapRect, treasure: Treasure) -> MKMapRect in
Is that some kind of function or something? What is the output? Im not quite understand meaning of that construction (struct: struct, someClass: someClass) -> Struct in
What is that logic? What is the meaning of "in"?
If you wondering, treasure is custom class that contain coordinate properties - latitude, longitude, etc.
I understand the "whole" meaning of that code snippet, but syntax of that line confuse me a bit..
Could you provide an explanation? Thanks a lot!
In Swift there are two ways to declare a function: with func, and with a closure expression:
// this is a function that takes an Int and returns a String
func f(i: Int) -> String { return i.description }
f(1) // returns "1"
// this is also a function that takes an Int and returns a String
let g = { (i: Int) -> String in return i.description }
g(1) // returns "1"
The latter is a closure expression – a quick way of defining a new function inline. They are most commonly used with functions that take functions (for example map, which takes an array and a function that transforms an element of that array, and runs the function on each element creating another array).
The syntax for closure expressions is they start, within braces, with arguments and return type, and then an in, and then the function body. Unlike with func, which starts with the func keyword, then the arguments and return type, followed by the function body within braces.
You don't always see the in because it can be left off. There are lots of shorthands that allow you to skip the arguments and return type (and the return keyword) altogether. But sometimes you need to give them, and then you need the in keyword.
You can read more about closure expressions in the Apple Swift book. You can read more about functions and closure basics here.

Odd xcode error when calling defined func in Swift

I have the following function defined in a .swift file in a new project I'm creating:
func createCircle(xPos: Int, yPos: Int) {
// do code here
}
For some reason when I try to call it using the following code xcode displays an error stating "Missing argument label 'yPos:' in call".
createCircle(100, 100)
The odd thing is it treats yPos different than xPos - if I include xPos: in the calling function it highlights the line and says "Cannot convert the expression's type '$Tf' to type 'IntegerLiteralConvertable'". So the following is what I end up with in order to call the aforementioned function:
createCircle(100, yPos: 100)
Am I missing something obvious or is this an xcode beta bug?
According to the Swift documentation
Section - Methods - Local and External Parameter Names for Methods
"Specifically, Swift gives the first parameter name in a method a
local parameter name by default, and gives the second and subsequent
parameter names both local and external parameter names by default."
Judging from your error, it seems like you're using a method and not a function. You don't need to provide the name for the first parameter but you must for subsequent parameters but this behaviour can be changed with the _ (underscore character).
class MyCircle {
var xPos: Double = 0.0;
var yPos: Double = 0.0;
func createCircle(x: Double, _ y: Double) {
// insert create circle logic here.
}
}
var cir = MyCircle();
cir.createCircle(100, 100);
By using the underscore for subsequent parameters you don't have to provide the label for them when calling the method.

Resources