Properties: Associated with a type
Variables: Not associated with a type
See the Swift Programming Language iBook for more information.
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"
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 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
.
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 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 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 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 before myProperty
is set. The new value is available as newValue
, and the old value is still available as myProperty
.didSet
is called after myProperty
is set. The old value is available as oldValue
, and the new value is now available as myProperty
.Note:
didSet
andwillSet
will not be called in the following cases:
- Assigning an initial value
- Modifying the variable within its own
didSet
orwillSet
oldValue
and newValue
of didSet
and willSet
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.