Start learning free

LESSON 203 OF 415 · FUNCTIONS & CLASSES

Classes in Swift: Properties, Initializers and Methods

Lesson Read the full explanation

Swift is an object oriented programming language. Almost everything in Swift is an object, with its attributes and methods.

Class creates a user-defined data structure, which holds its own data members (attributes) and member functions (methods), which can be accessed and used by creating an instance of that class.

Classes are like a blueprint for objects outlining possible behaviors and states that every object of a certain type could have.

Classes are defined via the keyword class, like this:

// Define an empty class Employee
class Employee {

}

Objects/Instances

An Object is an instance of a Class. A class is like a blueprint while an instance is a copy of the class with actual values. It's not an idea anymore, it's an actual employee, like a person named "Andrew" who is 30 years old.

You can have many employees to create many different instances, but without the class as a guide, you would be lost, not knowing what information is required.

After a class is defined, we can create objects of the class like this:

// Define an empty class Employee
class Employee {

}

// inside main function:
var employee = Employee()

Attributes/Properties

A class attribute is a Swift variable that belongs to a class: every object of this class has its own copy of it. Let's add some attributes to our Employee class:

class Employee {
    var name: String = ""
    var age: Int = 0
}

// inside main function:
var emp1 = Employee()

emp1.name = "Andrew"
print(emp1.name) // prints "Andrew"

var emp2 = Employee()

emp2.age = 40
print(emp2.age) // prints 40

We added two properties: the String name and the Int age. Then, we created two different Employee objects emp1 and emp2.

The attributes of objects can be accessed and modified using the dot operator (.), like we did above with emp1.name and emp2.age.

The keyword var used inside the class declares a mutable stored property. name and age are mutable properties, which means they can be accessed and changed from anywhere in the code.

Constructors

In real life, we want to set the attributes specific to each object when creating it. For example, an employee named Andrew of 30 years old and another one named Mary of 25 years old. Here the constructor comes to rescue.

A constructor is a special type of method (function) which is used to initialize the instance members of the class.

In Swift the constructor is called init and is always called when an object is created.

Let's add a constructor to our Employee class:

class Employee {
    var name: String
    var age: Int

    // constructor:
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// inside main function:
let emp1 = Employee(name: "Andrew", age: 30)

print(emp1.name)

let emp2 = Employee(name: "Mary", age: 25)

print(emp2.age)

// prints "Andrew" and 25 on different lines

The "self"

Every object in Swift has access to itself through an important reference called self.

The self reference is an implicit parameter to all member functions. Therefore, inside a member function, self may be used to access and manipulate the attributes of that object, like we did above with self.name = name.

Member functions

Member functions are functions that belong to the class:

class Employee {
    var name: String
    var age: Int

    // constructor:
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    // member functions:
    func printName() {
        print(name) // it is not mandatory to use "self" to access a property
    }

    func printEmployee() {
        printName()
        print(age)
    }
}

// inside main function:
let emp1 = Employee(name: "Andrew", age: 30)

emp1.printEmployee() // prints "Andrew", 30

let emp2 = Employee(name: "Mary", age: 25)

emp2.printEmployee() // prints "Mary", 25

As you can see, we access functions just like we access attributes: using the dot syntax (.).

The function call uses the attributes of the object it was called on. That's why the first printEmployee() prints "Andrew" and 30 and the second prints "Mary" and 25.


Assignment
Follow the Coding Tutorial and let's write some classes.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 8
    Ctrl + Enter to check

    SWIFT · FUNCTIONS & CLASSES

    Classes in Swift, explained

    What a class is

    A class is a blueprint for objects. It lists the data every object carries, called properties, and the actions every object can perform, called methods. An object, or instance, is one concrete thing made from that blueprint: one employee named Andrew who is 30, another named Mary who is 25. You define the blueprint once and create as many instances as you need.

    The simplest class is an empty one, created by calling its name like a function. Swift has no new keyword:

    class Employee {
    }
    let employee = Employee()
    

    Properties

    A property is a variable that belongs to each instance. Declare it with var for a changeable value or let for a fixed one, and give it a type. Read and change it with the dot operator:

    class Employee {
        var name: String = ""
        var age: Int = 0
    }
    let emp1 = Employee()
    emp1.name = "Andrew"
    let emp2 = Employee()
    emp2.age = 40
    print(emp1.name, emp1.age, emp2.name.isEmpty, emp2.age)
    
    Andrew 0 true 40
    

    Each instance has its own copy of the properties, so changing emp1.name leaves emp2.name as it was. Notice that emp1 is a let and yet its name changes. A class is a reference type: the constant holds a reference to the object, and the object's own var properties can change. What the constant forbids is pointing emp1 at a different object. Assigning an instance to a second variable gives you another reference to the same object, not a copy.

    Initializers

    Setting properties one by one after creation is clumsy and easy to forget. An initializer, written init, sets them up when the object is created. Swift requires every stored property to have a value by the time init finishes, which is why a property with no default value is allowed as long as init assigns it:

    class Employee {
        var name: String
        var age: Int
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
    }
    let emp1 = Employee(name: "Andrew", age: 30)
    print(emp1.name, emp1.age)
    
    Andrew 30
    

    Inside init, the parameter name hides the property of the same name. self refers to the object being built, so self.name = name stores the parameter in the property. In Swift, parameter names are also labels at the call site: Employee(name: "Andrew", age: 30). Put _ in front of a parameter to drop its label, so init(_ title: String) is called as Job("Software Engineer"). Calling it with a label anyway is a compile error ("extraneous argument label").

    Methods

    A method is a function declared inside the class. It runs on one instance and can use that instance's properties by name. Writing self. is optional unless a parameter has the same name:

    class Employee {
        var name: String
        init(name: String) { self.name = name }
        func greet() {
            print("Hi, I am \(name)")
        }
    }
    Employee(name: "Mary").greet()
    
    Hi, I am Mary
    

    The text \(name) is string interpolation: Swift evaluates the expression inside the parentheses and inserts it into the string.

    The exercise, step by step

    The task is to build a Job class and use it in mainFunction.

    1. Declare the class. class Job { } at the top of the file.
    2. Add the property. var title: String stores the job's title. It needs no default, because the initializer will always set it.
    3. Add the initializer. init(_ title: String) takes one parameter without a label, so a job is created with Job("Software Engineer").
    4. Store the value. Inside init, self.title = title copies the parameter into the property.
    5. Declare the method. func hireMe() takes no parameters.
    6. Print the message. Inside hireMe, print("You're hired as a \(title)") uses interpolation. The property title needs no self..
    7. Create the object. In mainFunction, let job = Job("Software Engineer").
    8. Call the method. job.hireMe() prints the message.
    class Job {
        var title: String
        init(_ title: String) {
            self.title = title
        }
        func hireMe() {
            print("You're hired as a \(title)")
        }
    }
    
    class Solution {
        func mainFunction() {
            let job = Job("Software Engineer")
            job.hireMe()
        }
    }
    

    Calling mainFunction() prints You're hired as a Software Engineer. Changing job.title first changes the message, because title is a var.

    Common mistakes

    • Leaving a property unset. If init never assigns title, the compiler reports "return from initializer without initializing all stored properties".
    • Forgetting self. when names clash. Without it, title = title refers to the parameter on both sides, and the compiler rejects it because a parameter is a constant.
    • Using a label where there is none. Job(title: "x") fails when the initializer declares _ title.
    • Expecting a copy. let b = a for a class instance makes b and a the same object.

    Key takeaways

    • A class defines properties and methods; instances are made by calling the class name with no new.
    • init must give every stored property a value, and self names the current object.
    • Parameter names are labels at the call site unless you write _.
    • Classes are reference types, so assigning an instance shares it.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free