Class
With a Swift class
we group together related data and methods—we form a unit. And with many units together we create complex models.
With init
methods, we construct class
instances. Classes are a reference type—they are stored in a referenced region of memory. Structs are not.
This program declares a class
named Box. There are two stored properties on the class
—width and height. These are stored in the memory for the class
.
Init()
is a special method on the class
. It is called when we create a new instance by calling Box()
.self
" keyword (present in init
and area) refers to the current instance of the class
.class
instance with width 10 and height 5. We call the area()
func
, which computes the result.class Box { var width: Int var height: Int init(width: Int, height: Int) { self.width = width self.height = height } func area() -> Int { // Return width times height. return self.width * self.height } } // Create new instance of Box class. let test = Box(width: 10, height: 5) // Compute area for Box instance. let area = test.area() // Display area. print(area)50
init
A class
may have more than one init
method. We can provide overloaded init
methods that have formal parameter lists.
String
, Int
argument list, or use just an Int
.class
has an optional stored property, like "model," we do not need to assign it in all the init
methods.class Unit { var model: String? var modelId: Int init(model: String, modelId: Int) { // This init requires two arguments. self.model = model self.modelId = modelId } init(modelId: Int) { // Only one argument. self.modelId = modelId } } // Create a Unit with the 2-argument init. let example = Unit(model: "ABC12", modelId: 12) print(example.modelId) // Use 1-argument init. let example2 = Unit(modelId: 13) print(example2.modelId)12 13
Swift provides the deinit keyword. This is used to run code before deinitialization. The deinit code is run automatically.
class
instance to nil
, the deinit code block is executed. In this example, we create an Optional
Item.nil
, the deinit block is run. Cleanup of system resources can occur here.class Item { init() { print("init called") } deinit { // Called whenever class stops existing. print("deinit called") } } // Create optional Item variable. var i: Item? = Item() // Set optional to nil to force deinit. i = nilinit called deinit called
init
An init
can be failable. We use the "init
?" syntax for this. Here we disallow a Square class
to be created if the width or height is less than or equal to zero.
init
method returns an Optional
class
instance. The return value may be nil
.let
-conditional statement (or with another Optional
test).init
makes sense if the class
cannot logically exist if an argument is invalid.class Square { var width: Int! // Has default value of nil. var height: Int! init?(width: Int, height: Int) { // Do not allow negative width or height. if width <= 0 { return nil } if height <= 0 { return nil } self.width = width self.height = height } } // The initializer succeeds. var square = Square(width: 10, height: 20) if let s = square { print(s.width!) print(s.height!) } // The failable initializer returns nil. var squareNegative = Square(width: -1, height: -1) if let s = squareNegative { // Not reached. print(s.width!) print(s.height!) }10 20
CustomStringConvertible
A type can inherit from CustomStringConvertible
(formerly Printable). This means the class
has a description property.
String
property. This should return a string
that contains important data about the class
instance.class
provides a description that includes its size Int
. Print()
displays the description when passed a class
instance.class Item: CustomStringConvertible { var size: Int init(size: Int) { self.size = size } var description: String { // Custom string. return "Item: \(self.size)" } } // Create new instance. // ... Print using CustomStringConvertible description. let item = Item(size: 10) print(item) // Access the description directly. let description = item.description print("Description = \(description)")Item: 10 Description = Item: 10
Some accesses to a class
are more complex: they might use two or more arguments. A subscript can be used to make accesses to a class
similar to those of an array or dictionary.
With classes and structs, we build programs with more reusable parts. In larger programs, this leads to simplifications. Classes can even reduce copying and improve performance.