How do I interpret a Swift function declaration?
internal
is the scope?
This is an access modifier. It means that only code in the same module can see/call this symbol.
internal
is implicit if you leave it off, and has meaning primarily for when you're making frameworks — an app that links a framework can see only the framework's public
symbols, but code within the framework can see other internal
symbols in the framework. (And code in one type within the framework can't see private
symbols inside another type.)
func
is a keyword that declares method/functions?
Yes. In Swift, a "method" is just a func
tion declared in the scope of a type (class, struct, protocol, enum).
tableView
is the name of the method?
Yes... in one sense. It's what is often called the "base name" of a function/method — the part before the open-parenthesis (
. The full name of the method, which people use when trying to unambiguously refer to this method versus others, includes all the argument labels: tableView(_:cellForRowAt:)
. (Even a full name isn't unambiguous in Swift, though, because functions/methods can be overloaded on parameter/return types.)
Usually a function name is a verb phrase, describing the action performed by a function or characterizing the result, but there's a longstanding convention otherwise in delegate/datasource protocols. (And this method is from the UITableViewDataSource
protocol.) In such protocols, the "base name" of the function to name the object that's delegating some action.
What is
_tableView
? Is this the name of a parameter? If so, why do we need the underscore whencellForRowAt
does not have an underscore, assumingcellForRowAt
is also a name?
It's not _tableView
, it's _ tableView
— note the space. The underscore generally means "ignore this" in Swift. In this case, the underscore takes the place of an argument label, meaning that the caller of this method doesn't write one for the first parameter:
let cell = tableView(myTableView, cellForRowAt: selectedIndexPath)
^ nothing here, just the value being passed as an argument
Is
UITableView
a parameter type?
IsIndexPath
a parameter type?
Yes.
What is
indexPath
incellForRowAt indexPath
? Why are there 2 words?
cellForRowAt
is an argument label. indexPath
is the internal (to your implementation) name of the parameter.
Argument labels are used by whoever calls your function — e.g. a call site for this looks like:
let cell = tableView(myTableView, cellForRowAt: selectedIndexPath)
Parameter names are how you refer to that value within the function body:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
self.doSomethingWithCellData(indexPath)
...
}
UITableViewCell
is the return type, right?
Right. If you don't include a return
statement in your implementation of this method, or return
anything that isn't a UITableViewCell
, the compiler gets upset.
Swift: difference between function calling
When encapsulated in a class (or struct or enum), the first parameter name of a method is not included externally, while all following parameter names are included externally. The parameters which are not included externally, you don't have to give names for them when calling the method. But for externally included ones you have to.
Your method incrementBy(amount: Int, numberOfTimes : Int)
is encapsulated in your class that's why the second parameter is automatically externally included. Which means you have to type numberOfTimes
before providing value to parameter. That's why you must call it like:
counter.incrementBy(1, numberOfTimes : 3)
Your second method func sampleFunc(firstName : String, lastName : String)
is not enclosed in your class. That's why you don't have to provide name for its parameters. Which is why you can call it like:
sampleFunc("Abel", "Rosnoski")
You can read more details here.
Edit: As User3441734 kindly pointed out (And I quote) "There is one exception. init with parameters always requires named parameter, if the external name is not specified as _ ". You can read more about Customizing initialization here.
What is the meaning of the : in Swift function signatures and why is there no comma when it seems there should be one?
The convention, frequently seen in documentation, is a concise way of referring to a function, using only the function name and argument labels.
So consider this function declaration:
func insert(_ objects: [Any], at indexes: IndexSet)
This is
- a method called
insert
; - the first parameter name is called
objects
, this parameter has no argument label (designated with the_
) and has a type of[Any]
; and - the second parameter name is
indexes
, its argument label isat
and has a type ofIndexSet
.
So you call it like so:
insert(someObjects, at: someIndex)
When you call it, you don’t care what the parameter names that are used inside that function, but rather just what the argument labels are. So, the convention when referring to that method in documentation is to omit the parameter names and types and just use the function name and the argument labels, but no comma:
insert(_:at:)
Note, you’d never actually use this syntax in your code. This is just a documentation convention employed to distill long function declarations down to something more manageable and concise:
For more information about argument labels and parameter names, see Function Argument Labels and Parameter Names
What does _: mean in Swift?
It's a way of stating the name of the function. The function might be declared like this:
func recordResponse(s:String) {
// ...
}
Now, by default, the s
is an internal parameter name only; the external parameter name is suppressed. So we need a notation that describes the function, recordResponse
, as taking one parameter with no external name. That notation is recordResponse(_:)
. The colon follows each parameter name — here there is only one parameter, and has no external name, which is what the underscore indicates.
In the usage you are asking about, this notation is just that: a notation. It's a convention for giving the name of the function in a complete way, when humans talk to humans (as in a tutorial). But in Swift 2.2, this notation will become very important, because it will be part of the language — it's how you'll form a function reference. That is, it will be Swift's own name for the function.
In Swift, what does the ! symbol mean in a function signature?
This isn't quite a duplicate — there's some subtlety to implicitly unwrapped optionals in function signatures beyond their usage elsewhere.
You see implicitly unwrapped optionals in API imported from ObjC because that's the closest Swift approximation of an object that's expected to be there but which can be nil. It's a compromise for imported API — you can address these variables directly like in ObjC, and you can test them for nil using Swift optional syntax. (There's more about Apple's rationale for this in the Advanced Interoperability talk from WWDC14.) This pattern also applies to the IBAction
declarations inserted by Interface Builder, since those methods are in effect getting called from ObjC code, too.
As you seem to have suspected, Swift wraps the possible nil in an optional when bridging from ObjC, but the !
in your function implementation's declaration unwraps the value so you can use it directly. (At your own risk.)
Since Swift 1.2 (Xcode 6.2 in Spring 2015), ObjC APIs can be annotated with nonnull
and nullable
, in which case the Swift interface to those APIs uses either a non-optional type or a fully optional type. (And since Swift 2.0 / Xcode 7.0, nearly all of Apple's APIs are audited to use nullability annotations, so their Swift signatures don't use much !
anymore.)
What's less well-known about this is that you're free to change the optionality of parameters when you implement your own Swift functions that get called by ObjC. If you want the compiler to enforce that sender
in your action method can never be nil, you can take the !
off the parameter type. If you want the compiler to make sure you always test the parameter, change the !
to a ?
.
What are the differences between functions and methods in Swift?
After a few hours of reading and experimenting, here are the things that I found out:-
Functions in Swift
Functions are self-contained chunks of code that perform a specific
task. You give a function a name that identifies what it does, and
this name is used to “call” the function to perform its task when
needed.
Resource: Official Apple Documentation on Functions in Swift
Function Parameter Names
However, these parameter names are only used within the body of the
function itself, and cannot be used when calling the function. These
kinds of parameter names are known as local parameter names, because
they are only available for use within the function’s body.
It means that by default, all the parameters for Function are local parameters.
But, sometimes we want to indicate the purpose of each parameter. So, we can actually define an external parameter name for each parameter. Example Code:
func someFunction(externalParameterName localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
Another way to make the external parameter name is using hash symbol (#) to shorten the name.
func someFunction(#localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
To call the above functions with external parameter, you may use
someFunction(localParameterName:10)
Methods in Swift
Methods are functions that are associated with a particular type.
Classes, structures, and enumerations can all define instance methods,
which encapsulate specific tasks and functionality for working with an
instance of a given type.
Resource: Official Apple Documentation on Methods in Swift
However, the default behavior of local names and external names is
different for functions and 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.
Code below shows the differences for default and non-default parameters for method in Swift.
import Foundation
import UIKit
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Default methods calling
var dailyStatement = greet("Rick", day: "Tuesday")
println(dailyStatement)
//First parameter is also an external parameter
var dailyStatement2 = greet2(name:"John", day: "Sunday")
println(dailyStatement2)
}
//Default: First Parameter is the local parameter, the rest are external parameters
func greet (name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
//Use Hash symbol to make the First parameter as external parameter
func greet2 (#name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
}
I might miss some important details. Hope someone can provide a better answer.
Why does a function call require the parameter name in Swift?
Update for Swift 2.0: Now functions behave identically to methods, and for both, by default:
- the first parameter has no external name; and
- the other parameters have an external name identical to the internal name.
Other than that, the rules below still apply, except that the #
shorthand syntax is now gone.
Here's a more general answer: functions behave differently when defined as true functions outside a class, and when defined as methods. Moreover, init methods have a special rule.
Functions
Suppose you define this:
func multiply1(f1: Double, f2: Double) -> Double {
return f1 * f2
}
Parameter names are here only local to the function, and cannot be used when calling the function:
multiply1(10.0, 10.0)
If you want to force using named parameters when calling the function, you can. Prefix each parameter declaration with its external name. Here, the external name of f1
is f1param
, and for f2
, we use the shorthand where we prefix it by #
to indicate that the local name is to be used as the external name as well:
func multiply2(f1param f1: Double, #f2: Double) -> Double {
return f1 * f2
}
Then, named parameters must be used:
multiply2(f1param: 10.0, f2: 10.0)
Methods
Things are different for methods. By default, all but the first parameter are named, as you've discovered. Suppose we have this, and consider the multiply1
method:
class Calc {
func multiply1(f1: Double, f2: Double) -> Double {
return f1 * f2
}
func multiply2(f1param f1: Double, f2: Double) -> Double {
return f1 * f2
}
func multiply3(f1: Double, _ f2: Double) -> Double {
return f1 * f2
}
}
Then, you have to use the name of the second (and following, if any) parameters:
let calc = Calc()
calc.multiply1(1.0, f2: 10.0)
You can force to use a named param for the first argument by providing an external name for it, like for functions (or prefixing its local name with #
if you want to use the same external name as its local name). Then, you have to use it:
calc.multiply2(f1param: 10.0, f2: 10.0)
Finally, you can declare an external name of _
for the other following arguments, indicating that you want to call your method without using named parameters, like this:
calc.multiply3(10.0, 10.0)
Interoperability note: If you prefix class Calc
with the @objc
annotation, then you can use it from Objective-C code, and it is equivalent to this declaration (look at parameter names):
@interface Calc
- (double)multiply1:(double)f1 f2:(double)f2;
- (double)multiply2WithF1param:(double)f1 f2:(double)f2;
- (double)multiply3:(double)f1 :(double)f2;
@end
Init Methods
The rule differs a bit for init
methods, where all parameters have an external name by default. For instance, this works:
class Calc {
init(start: Int) {}
init(_ start: String) {}
}
let c1 = Calc(start: 6)
let c2 = Calc("6")
Here, you have to specify start:
for the overload that accepts an Int
, but you must omit it for the overload that accepts a String
.
Interoperability note: this class would get exported to Objective-C like this:
@interface Calc
- (instancetype)initWithStart:(NSInteger)start __attribute__((objc_designated_initializer));
- (instancetype)init:(NSString *)start __attribute__((objc_designated_initializer));
@end
Closures
Assume you define a closure type like this:
typealias FancyFunction = (f1: Double, f2: Double) -> Double
The parameter names will behave very similar to those in a method. You will have to provide the names to the parameters when calling the closure unless you explicitly set the external name to _.
For example, executing the closure:
fund doSomethingInteresting(withFunction: FancyFunction) {
withFunction(f1: 1.0, f2: 3.0)
}
As a rule of thumb: even if you dislike them, you should probably try to keep using named parameters at least whenever two parameters have the same type, in order to disambiguate them. I'd also argue that it's good to also name at least all Int
and Boolean
parameters.
What is _: in Swift telling me?
The _
is used to define that the parameter is not named
If you have multiple _
it states that you do not need to name the parameters in your function call
func myFunc(name:String, _ age:String){
}
myFunc(“Milo", "I'm a really old wizard")
If you do not use the underscore you would use
myFunc(“Milo”, age: "I'm a really old wizard")
The _
is not necessary for function calls. It is just used to indicate that something does not need to have a name.
In regards to how you would refer to your function, You would not have to pass any name for the function call.
But since you also don’t define a parameter type this seems to me like an invalid example (it at least doesn’t work in Xcode 7 with Swift 2.0)
Edit:
Since Swift 3.0
myFunc(name: “Milo”, age: "I'm a really old wizard")
Should be used
Related Topics
iOS - Add Image and Text in Title of Navigation Bar
Codable Class Does Not Conform to Protocol Decodable
When Calling a Function in Swift, What Does Each Part Mean
Swift Convert Time to Time Ago
Build Input File Cannot Be Found' Swift 4.2, Xcode 10.0
Does Swift Compile to Native Code
How to Hide Status Bar and Navigation Bar When Tap Device
How to Change the Z Index or Stack Order of Uiview
Xcode 6.3 Code Completion Too Slow
Fill Circle with Wave Animation in Swiftui
How to Define Static Constant in a Class in Swift
How to Create Uicollectionviewcell Programmatically
Fastlane "Nokogiri Requires Ruby Version >= 2.3.0." Error
iOS 11 Large Title Navigation Bar Snaps Instead of Smooth Transition
Convert Date to Integer in Swift
What Is the Replacement for Isdigit() for Characters in Swift