Comparing Classes vs. Structs in Swift

Written by: Reinder de Vries, May 17 2017, in App Development

Comparing Classes vs. Structs in Swift

What’s the difference between classes vs. structs? They’re so alike! It’s best to use structs in very specific scenarios – but which ones?

In this article, you’re going to take a look into classes vs. structs. When do you use a class, and when do you use a struct? What is Protocol Oriented Programming, and how does it work?

Structs are a very powerful feature of Swift, and they can help to make your code more reusable, more flexible, and less tightly coupled. And last but not least, they sharpen your skills as an app developer!

Let’s dive in!

Classes vs. Structs: At A Glance

First, let’s take a look at what classes and structs (short for “structures”) have in common:

  • They can define properties to store values, and they can define functions
  • They can define subscripts to provide access to values with subscript syntax (like human["legs"])
  • They can define initializers to set up their initial state, with init()
  • They can be extended with extension (this is important!)
  • They can conform to protocols, for instance to support Protocol Oriented Programming

Out of the box, classes are more versatile than structs (at a cost), and support a few more capabilities that structs don’t have:

  • Classes can inherit from another class, like you inherit from UIViewController to create your own view controller subclass
  • Classes can be deinitialized, i.e. you can “call” a function before the class is destroyed
  • You can create one or more references to a single class (important!)

What are the implications of these differences? First off: classes are reference types, and structs are value types.

This means that, if you pass a class instance as an argument to a function, that function will create a “link”, called a reference, between the original object and the variable inside the function. Instead of copying the variable, a simple connection is created.

Structs are value types, so they’ll get copied when you reference them. When you pass a struct into a function, inside the function it’ll be a new copy of the original value. A typical example of a struct is String.

Here’s an example:

  • Reference Type: Bob has a phone number. He gives it to Alice. Alice doesn’t write down the phone number for herself, but instead remembers that Bob has it. When she needs the phone number, she asks Bob. When Alice accidentally changes one digit of the phone number, Bob’s phone number changes too. (You could picture this as Bob and Alice both holding the piece of paper the phone number is written on.)
  • Value Type: Bob has a phone number, and he gives it to Alice. Alice writes it down and now has her own copy. When she accidentally changes it, only her copy changes, and not the original phone number Bob has.

It’s in the name: value types are passed by copying a value, and reference types are passed by creating a reference.

One exception exists: structs captured in a closure, unless explicitly noted, will create a reference to the original struct.

Grab My Free iOS Development Course

Get complementary access to my course, Zero to App Store, and learn how you can build a real-time chat app with Firebase and Swift!

Yes, Send Me The Free Course!

Structs Are Awesome

So what are structs good for? It’s preferrable to use structs in these cases:

  • For values that are small and easy to copy. Think about database objects you want to pass around in your code, like NewsItem, Task or User. Since they’re so small and well-defined, it’s much easier to pass them around as structs.
  • In a multi-threaded environment, for instance with a database connection that’s opened in a different thread, structs are safer. They can be copied from one thread to another thread, without running the risk of a race condition or deadlock. Classes do not have this inherent safety, unless they’re deliberately made thread-safe.
  • When the properties of a struct are mostly value types too, like String, it makes sense to wrap them in a struct instead of a class.

When you don’t need inheritance, or want to use Protocol Oriented Programming, it makes sense to use structs, too.

Just so we’re on the same page, this is how you define and use a struct:

struct NewsItem
{
    var title:String = ""
    var url:String = ""
}

var item = NewsItem()
item.title = "Comparing Classes vs. Structs in Swift"
item.url = "https://learnappmaking.com/classes-structs-comparison-swift-programming"

print(item)
// Output: NewsItem(title: "Comparing Classes vs. Structs in Swift", url: "https://learnappmaking.com/classes-structs-comparison-swift-programming")

As you can see, the syntax is effectively the same as for defining and using a class. Instead of class [name] { ... you write struct [name] { ....

Speaking of classes…

Comparing Classes vs. Structs in Swift https://learnappmaking.com/classes-structs-comparison-swift-programmingClick To Tweet

What Classes Are Good For

What are classes good for, if you have structs? As noted before, classes have a few extra characteristics that structs don’t have:

  • Classes can inherit from another class, which you can’t do with structs. With classes, you can write class MyViewController : UIViewController to create a subclass of UIViewController. Conversely, structs can implement protocols.
  • Classes can be deinitialized, i.e. they can implement a deinit function, and you can make one or more references to the same class (i.e., classes are a reference type).

Inheritance is the most important difference between classes and struct. With classes, you can clearly define a parent-child connection between subclass and superclass.

A few examples:

  • MyViewController inherits from UIViewController
  • MyTableViewController inherits from InfiniteTableViewController to adopt “infinite scrolling”, which in turn inherits from UITableViewController
  • Car and Bike both inherit from Vehicle, because they both use the same “basic” set of characteristics like numberOfWheels and speed.

In these last two examples lies a danger: you can end up with a whole bunch of inherited classes, that all “decorate” the subclass with different functionalities. Think about SuperCar and MuscleCar, that both inherit from Car, and from Vehicle.

It’s easy to get lost in which class inherits what, even though, at first sight, it makes sense to structure your classes like this. What if SuperCar inherits a function that it doesn’t need from Vehicle? What if you want to create a SuperBike, that’s similar to a SuperCar, but you can’t “inherit” or share those characteristics because they’re in different subclass-superclass hierarchies?

As a rule of thumb, it only makes sense to use classes for these scenarios1:

  • When copying or comparing instances doesn’t make sense, e.g. with Window or UIViewController. It doesn’t make sense to copy an app window, since there’s only one active at a time, and it often doesn’t make sense to copy a view controller either – you’d just create a new one.
  • When the “lifetime” of an instance is tied to external effects, e.g. for DatabaseConnection or TemporaryFile. It doesn’t make sense to create two copies of a reference to a file on the disk, after all, they both reference the same data, and represent that data in code. (You don’t write a phone number twice in an address book, right?)
  • When instances are just “conduits” for external states, e.g. for CGContext. Sometimes you need a helper or wrapper class to get things done: an API or a reference to an online resource. In those cases the class is only a conduit, something that passes along information, and it doesn’t make sense to create a copy of that.

As you can see, “to copy, or to reference” is the defining factor to choose between classes or structs. If it makes sense to copy a value, pick structs, if it makes sense to reference a value (and not copy), then choose classes.

Related: The Swift 3 Cheatsheet [Updated]

A Practical Application: Protocol Oriented Programming

Structs are perfect for Protocol Oriented Programming. POP is a bit of a twist on Object Oriented Programming, with which you’re probably familiar.

Protocol Oriented Programming, among other things, hinges on two principles:

  • Structs can adopt protocols, just like classes
  • Protocols can be extended

Remember the SuperCar and SuperBike problem from before? Let’s use Protocol Oriented Programming to solve it:

  • You have one class called Vehicle, that has a property wheels and a function move(). A “nominal” vehicle has 4 wheels, and a speed of 40 km/h.
  • Instead of creating a rigid hierarchy of Vehicle -> Car -> SuperCar and Vehicle -> Bike -> SuperBike, you’re going to create a protocol Superize that will turn any vehicle in a super-vehicle: super car, muscle car, super bike, super boat.
  • The downside of protocols is that you have to implement them. Protocols define “rules” a class needs to conform to. However, with Protocol Oriented Programming and protocol extension you can give a protocol a default implementation. This means you can decorate any class with any protocol, without actually implementing those protocols!

Related: How To Use Generics In Swift 3

Thanks to Protocol Oriented Programming, and protocol extensions, you can make a very flexibile code structure. Especially if you want to create more super-vehicles (car, boat, bike, etc.) you can simply put the same protocol on any of them, without having to make a rigid class hierarchy.

Here’s the code:

// Define the protocol
protocol Superize
{
    func superspeed()
}

// Extend the protocol with a default implementation
extension Superize
{
    func superspeed()
    {
        print("Moving at super sonic light speed!!!")
    }
}

// Create a super vehicle with two wheels (a superbike)
struct Vehicle:Superize
{
    var wheels = 2
}

// Use the superbike
var bike = Vehicle()
bike.superspeed()
// Outputs: Moving at super sonic light speed!!!

Conclusion

So… that’s structs vs. classes for ya! You learned this:

  • The differences and similarities between structs and classes
  • When it’s best to use structs, and when it’s better to use classes
  • How structs and protocols come in handy, with Protocol Oriented Programming

Learn more:

Enjoyed this article? Please share it!

Comparing Classes vs. Structs in Swift https://learnappmaking.com/classes-structs-comparison-swift-programmingClick To Tweet

Written By: Reinder de Vries

Reinder de Vries is an indie app developer who teaches aspiring app developers and marketers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed over 50 apps for iOS, Android and the web, and his code is used by millions of users all over the globe. When Reinder isn't building apps, he enjoys strong espresso and traveling.

Grab My Free iOS Development Course

Get complementary access to my course, Zero to App Store, and learn how you can build a real-time chat app with Firebase and Swift!

Yes, Send Me The Free Course!

Comments & Thoughts