Methods
Methods are functions that belong to a particular type. Classes, structures, and enumerations can all define instance methods that work with an instance's data, and type methods that work with the type itself. This is one place Swift differs from C and Objective-C, where only classes can define methods.
Instance methods
An instance method is a function defined inside a type. It has access to all the instance's other methods and properties, and you call it with dot syntax on an instance.
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
let counter = Counter()
counter.increment()
counter.increment(by: 5)
print(counter.count) // → 6
Just like functions, method parameters have argument labels and parameter names, and follow the same rules for default values and so on.
The self property
Every instance has an implicit property called self that refers
to the instance itself. You rarely need to write it, because Swift assumes
you mean the current instance's property or method. You do need
self to disambiguate when a parameter name shadows a property.
struct Point {
var x = 0.0, y = 0.0
func isToTheRight(of x: Double) -> Bool {
return self.x > x // self.x = property, x = parameter
}
}
let p = Point(x: 4.0, y: 5.0)
print(p.isToTheRight(of: 1.0)) // → true
Modifying value types from instance methods
Structures and enumerations are value types, and by default their properties
can't be changed from within an instance method. To allow it, mark the
method mutating. The method can then modify the instance's
properties, and the changes are written back to the original value when the
method ends.
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("(\(somePoint.x), \(somePoint.y))") // → (3.0, 4.0)
Watch out: you can't call a mutating method on a constant
of a value type. let fixedPoint = Point(...) followed by
fixedPoint.moveBy(...) is a compile-time error, because the value
can never change.
Assigning to self within a mutating method
A mutating method can replace the entire instance by assigning a brand-new
value to self. For enumerations, this is how a method can switch
the instance to a different case.
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x dx: Double, y dy: Double) {
self = Point(x: x + dx, y: y + dy) // replace the whole value
}
}
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off: self = .low
case .low: self = .high
case .high: self = .off
}
}
}
var light = TriStateSwitch.low
light.next()
print(light) // → high
Type methods
Type methods are called on the type itself, not on an
instance. Mark them with static. For classes you can instead use
class, which allows subclasses to override the method. Inside a
type method, self refers to the type, and you can call other type
methods without qualification.
struct TemperatureConverter {
static func celsius(fromFahrenheit f: Double) -> Double {
(f - 32) * 5 / 9
}
}
print(TemperatureConverter.celsius(fromFahrenheit: 212)) // → 100.0
class Vehicle {
class func describe() -> String { "A generic vehicle" }
}
class Car: Vehicle {
override class func describe() -> String { "A car" }
}
print(Vehicle.describe()) // → A generic vehicle
print(Car.describe()) // → A car
Tip: use static by default for type methods.
Reach for class only when you specifically want subclasses to be
able to override the behavior.
Recap
Methods give your types behavior. Instance methods operate on a single
instance through self; mutating methods let value
types change (or even fully replace) themselves; and type methods attach
behavior to the type as a whole. Next you'll learn subscripts — a method-like
shortcut for accessing elements by index or key.