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 = 10Variables can have their values changed:
num = 20 // num now equals 20Unless they’re defined with let:
let num: Int = 10 // num cannot changeSwift 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 FloatVariable 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 5willSetis called beforemyPropertyis set. The new value is available asnewValue, and the old value is still available asmyProperty.didSetis called aftermyPropertyis set. The old value is available asoldValue, and the new value is now available asmyProperty.
Note:
didSetandwillSetwill not be called in the following cases:
- Assigning an initial value
- Modifying the variable within its own
didSetorwillSet
-
The parameter names for
oldValueandnewValueofdidSetandwillSetcan 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.