Before I can explain the difference between instance methods and type methods, you first need to understand what an instance is and what a type is. Let me show you an example. Fire up Xcode and create a playground. Remove the contents of the playground and declare a struct with name User
. The struct declares one constant property, name
of type String
.
struct User {
// MARK: - Properties
let name: String
}
User
is a type. We can create a user by invoking the memberwise initializer of User
. The user we created is an instance of User
.
let jane = User(name: "Jane")
What Are Instance Methods in Swift?
Now that you know what the difference is between an instance and a type, you may already know what the difference is between an instance method and a type method in Swift. Let's add a method to the User
struct.
struct User {
// MARK: - Properties
let name: String
// MARK: - Instance Methods
func greeting() -> String {
"Hello \(name)!"
}
}
The method we defined, sayHello()
, is an instance method. This suggests that we need an instance to execute the method. Let's use the user we created earlier to invoke the sayHello()
method.
let jane = User(name: "Jane")
jane.sayHello()
You can see the result in the results view on the left.
"Hello Jane!"
What happens if we call sayHello()
on the type, that is, the User
struct. The compiler throws an error, telling us that sayHello()
cannot be called on the User
struct. This isn't surprising because sayHello()
is an instance method and needs to be called on a User
instance.
What Are Type Methods in Swift?
You learned what an instance method is and that an instance method cannot be called on a type. This brings us to the question "What is a type method in Swift?" Let's create a type method to illustrate the difference. We add a type method to User
and name it createUser(with:)
. Notice that we prefix the type method with the static
keyword. That keyword tells the compiler createUser(with:)
is a type method.
struct User {
// MARK: - Properties
let name: String
// MARK: - Instance Methods
func sayHello() -> String {
"Hello, \(name)"
}
// MARK: - Type Methods
static func createUser(with name: String) -> User {
User(name: name)
}
}
We can confirm that createUser(with:)
is a type method by calling it on the User
struct.
let john = User.createUser(with: "John")
As the name suggests, a type method can only be called on the type that defines the type method. The compiler throws an error if we try to call createUser(with:)
on a User
instance.
What Are Class Methods in Swift?
The static
keyword isn't the only option you have to declare type methods. Let's start with a clean slate and define a class with name Book
. The Book
class has two properties, title
of type String
and author
of type String
. It defines an initializer to create a Book
instance.
class Book {
// MARK: - Properties
let title: String
let author: String
// MARK: - Initialization
init(title: String, author: String) {
self.title = title
self.author = author
}
}
We can use the static
keyword to add a type method to Book
. The favorites()
method is a type method that returns an array of Book
instances.
class Book {
// MARK: - Properties
let title: String
let author: String
// MARK: - Initialization
init(title: String, author: String) {
self.title = title
self.author = author
}
// MARK: - Type Methods
static func favorites() -> [Book] {
[
Book(title: "LOTR", author: "Tolkien")
]
}
}
Book.favorites()
We can also create a type method using the class
keyword. Let's add another type method, moreFavorites()
. This time we use the class
keyword.
class Book {
// MARK: - Properties
let title: String
let author: String
// MARK: - Initialization
init(title: String, author: String) {
self.title = title
self.author = author
}
// MARK: - Type Methods
static func favorites() -> [Book] {
[
Book(title: "LOTR", author: "Tolkien")
]
}
class func moreFavorites() -> [Book] {
[
Book(title: "The Hobbit", author: "Tolkien")
]
}
}
Book.favorites()
Book.moreFavorites()
The compiler doesn't throw any errors. It seems we can declare type methods using the static
keyword as well as the class
keyword. What is the difference? The difference becomes evident if we subclass the Book
class. Take a look at this example.
class FantasyBook: Book {
override static func favorites() -> [Book] {
[
Book(title: "The Silmarillion", author: "Tolkien")
]
}
override class func moreFavorites() -> [Book] {
[
Book(title: "The Book of Lost Tales", author: "Tolkien")
]
}
}
The compiler doesn't like this. It throws an error because we attempt to override a static method in a subclass.
Static methods cannot be overridden by subclasses of the class that defines the static method. There is another important difference. Enum and structs don't support inheritance, which means that you can only use static methods to define a type method on an enum or a struct. In summary, use the static
keyword for enums and structs or if subclasses of the class that defines the type method should not be allowed to override the type method. Use the class
keyword if subclasses of the class should be allowed to override the type method.