Variables & Properties
Remarks#
Properties: Associated with a type
Variables: Not associated with a type
See the Swift Programming Language iBook for more information.
Creating a Variable
Declare a new variable with var
, followed by a name, type, and value:
var num: Int = 10
Variables can have their values changed:
num = 20 // num now equals 20
Unless they’re defined with let
:
let num: Int = 10 // num cannot change
Swift infers the type of variable, so you don’t always have to declare variable type:
let ten = 10 // num is an Int
let pi = 3.14 // pi is a Double
let floatPi: Float = 3.14 // floatPi is a Float
Variable names aren’t restricted to letters and numbers - they can also contain most other unicode characters, although there are some restrictions
Constant and variable names cannot contain whitespace characters, mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number
Source developer.apple.com
var π: Double = 3.14159
var 🍎🍏: String = "Apples"
Property Basics
Properties can be added to a class or struct (technically enums too, see “Computed Properties” example). These add values that associate with instances of classes/structs:
class Dog {
var name = ""
}
In the above case, instances of Dog
have a property named name
of type String
. The property can be accessed and modified on instances of Dog
:
let myDog = Dog()
myDog.name = "Doggy" // myDog's name is now "Doggy"
These types of properties are considered stored properties, as they store something on an object and affect its memory.
Lazy Stored Properties
Lazy stored properties have values that are not calculated until first accessed. This is useful for memory saving when the variable’s calculation is computationally expensive. You declare a lazy property with lazy
:
lazy var veryExpensiveVariable = expensiveMethod()
Often it is assigned to a return value of a closure:
lazy var veryExpensiveString = { () -> String in
var str = expensiveStrFetch()
str.expensiveManipulation(integer: arc4random_uniform(5))
return str
}()
Lazy stored properties must be declared with var
.
Computed Properties
Different from stored properties, computed properties are built with a getter and a setter, performing necessary code when accessed and set. Computed properties must define a type:
var pi = 3.14
class Circle {
var radius = 0.0
var circumference: Double {
get {
return pi * radius * 2
}
set {
radius = newValue / pi / 2
}
}
}
let circle = Circle()
circle.radius = 1
print(circle.circumference) // Prints "6.28"
circle.circumference = 14
print(circle.radius) // Prints "2.229..."
A read-only computed property is still declared with a var
:
var circumference: Double {
get {
return pi * radius * 2
}
}
Read-only computed properties can be shortened to exclude get
:
var circumference: Double {
return pi * radius * 2
}
Local and Global Variables
Local variables are defined within a function, method, or closure:
func printSomething() {
let localString = "I'm local!"
print(localString)
}
func printSomethingAgain() {
print(localString) // error
}
Global variables are defined outside of a function, method, or closure, and are not defined within a type (think outside of all brackets). They can be used anywhere:
let globalString = "I'm global!"
print(globalString)
func useGlobalString() {
print(globalString) // works!
}
for i in 0..<2 {
print(globalString) // works!
}
class GlobalStringUser {
var computeGlobalString {
return globalString // works!
}
}
Global variables are defined lazily (see “Lazy Properties” example).
Type Properties
Type properties are properties on the type itself, not on the instance. They can be both stored or computed properties. You declare a type property with static
:
struct Dog {
static var noise = "Bark!"
}
print(Dog.noise) // Prints "Bark!"
In a class, you can use the class
keyword instead of static
to make it overridable. However, you can only apply this on computed properties:
class Animal {
class var noise: String {
return "Animal noise!"
}
}
class Pig: Animal {
override class var noise: String {
return "Oink oink!"
}
}
This is used often with the singleton pattern.
Property Observers
Property observers respond to changes to a property’s value.
var myProperty = 5 {
willSet {
print("Will set to \(newValue). It was previously \(myProperty)")
}
didSet {
print("Did set to \(myProperty). It was previously \(oldValue)")
}
}
myProperty = 6
// prints: Will set to 6, It was previously 5
// prints: Did set to 6. It was previously 5
willSet
is called beforemyProperty
is set. The new value is available asnewValue
, and the old value is still available asmyProperty
.didSet
is called aftermyProperty
is set. The old value is available asoldValue
, and the new value is now available asmyProperty
.
Note:
didSet
andwillSet
will not be called in the following cases:
- Assigning an initial value
- Modifying the variable within its own
didSet
orwillSet
-
The parameter names for
oldValue
andnewValue
ofdidSet
andwillSet
can also be declared to increase readability:var myFontSize = 10 { willSet(newFontSize) { print(“Will set font to (newFontSize), it was (myFontSize)”) } didSet(oldFontSize) { print(“Did set font to (myFontSize), it was (oldFontSize)”) } }
Caution: While it is supported to declare setter parameter names, one should be cautious not to mix names up:
willSet(oldValue)
anddidSet(newValue)
are entirely legal, but will considerably confuse readers of your code.