Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Swift - structs

2014 Swift Mac

In this episode of the Swift introduction series we’ll be looking at structs in Swift.

Previously we looked at classes in Swift, where reference types could be created with the class keyword containing a mixture of instance variables and methods. When references of objects are passed around, it is the pointer that is passed rather than the data that is copied.

Structs are value based types; the contents are stored as a contiguous block of memory, and when passed into a function or assigned to a variable, the structure as a whole is copied from one place to another. Although this sounds like it might be inefficient, structs can be assigned on the stack instead of in the heap, which means that when the function returns the memory is automatically cleaned up instead of having to be managed explicitly. A sufficiently smart compiler can even detect when logical copies are taking place and eliminate them; for example, a struct defined as a constant can be implicitly shared to other functions in the stack.

A struct is defined in Swift using the struct keyword:

```sh Defining a struct in Swift 1> struct Person {

  1. var firstName:String
  2. var lastName:String
  3. } 5> Person() error: missing argument for parameter ‘firstName’ in call Person() ^ 6> Person(firstName:”Alex”,lastName:”Blewitt”) $R0: Person = { firstName = “Alex” lastName = “Blewitt” } ```

Unlike classes, structs have an implicit initializer that sets all the field values, and the names of the parameters are defined based on the member names.

Also unlike classes, structs are copied by value, not by reference, so if the same struct is modified then the original does not get changed:

```sh Structs are passed by value 7> var alex = Person(firstName:”Alex”,lastName:”Blewitt”) alex: Person = { firstName = “Alex” lastName = “Blewitt” } 8> var alblue = alex // copies the values, not the reference alblue: Person = { firstName = “Alex” lastName = “Blewitt” } 9> alblue.firstName = “Al”; alblue.lastName = “Blue”; [alex,alblue] $R1: [Person] = 2 values { [0] = { firstName = “Alex” lastName = “Blewitt” } [1] = { firstName = “Al” lastName = “Blue” }


(Try the above example and replace `struct` with `class` --- you'll find that
the behaviour is different.)

Structs are used liberally in Apple's frameworks; things like `CGRect` and
`CGSize` are structs under the covers. These are presented as structs in
Swift as well. Structs can also contain other structs; a `CGRect` is defined
in `CGGeometry.h` and is defined to be:

struct CGRect { CGPoint origin; CGSize size; };


which contains two other structs:

struct CGPoint { CGFloat x; CGFloat y; }; struct CGSize { CGFloat width; CGFloat height; }; ```

At runtime, a CGRect is actually four CGFloat values back-to-back, with no other headers. That means that a C based array of 100 CGRect instances will take up 4x100xsizeof(CGFloat) bytes in memory; about as good as you can get without using data compression.

So, when should a struct be used and when should a class be used? If the data structures are fungible – that is, you can exchange one item for another without making a difference to the program – then a struct can safely be used. One pint of milk is very much like another pint of milk; they can be exchanged and it doesn’t really make any difference. If the data structures are non fungible – that is, the identity is important – then a class should be used instead. A person has identity, and even if you could clone them they wouldn’t be the same person, but rather two copies of a person with different identities.

The final observation is that structs cannot be placed inside an existing Cocoa container, like an NSArray. If the data structure needs to be stored inside containers or bound with widgets in the UI then an objective-c class should be used instead.


In next week’s episode, we’ll look at enums in Swift, and how they differ from the things we’ve seen so far. To subscribe to the series, add the <a href=”/Tag/swift/”Swift tag</a> feed to your reader.