Structures 101 in swift

Structures is not another type in swift. If you have background in C or objective C you will be impressed with the functionality of structs in swift. Structures have initialisers, methods, comfort to protocols have extensions...convinced?

Well, if start thinking that are like classes you are right but...only similar. Major difference is that structures are value types yet classes are reference types. When you assign a structure to another you essentially copy it, but in classes you share it because both instances will point to same address.  Additionally, classes supports inheritance but structures not.

Feel confused? You shouldn't. Lets start with the basics.

The structure groups relevant elements in one entity. Imagine a point in a 2D plane. If you have an app and you represent the point having two individual variables is not so easy and practical...try it if you don't believe! The solution is to use structures (or structs).

Lets define it:

struct Point {
    var x: Int
    var y: Int
}

Easy. Use the keyword struct, then the name and inside the curly braces the implementation, means member properties and later methods. So, this is the blueprint of the custom type Point. The creation of a real instance of a point is like that:

let p1 = Point(x: 1, y: 2)

Exactly, swift automatically creates a vanilla initialiser. So now you can instantiate your points and access its content using the dot syntax way. So...

p1.x = 5

No! you can't do this. Don't forget that p1 is let, which means constant and you don't have the permission to change it. The correct way is:

var p2 = Point(x: 2, y: 5)
p2.x = 3

so now the p2 will have x equal to 3 and y as before. By looking to points, personally, it reminds me the tuples. Could I have an initiliazer using tuples? Of course!

struct Point {
    var x: Int
    var y: Int

    init(point: (x: Int, y:Int)) {
        self.x = point.x
        self.y = point.y
    }
}

And you can use it like:

let p2 = Point(point: (1, 1))

At this point if you try to use the first swift-free initializer you will get an error. What happened??
Since you included a custom initializer in your design the free one becomes unavailable and you should implemented by hand. It's not difficult at all.

struct Point {
    var x: Int
    var y: Int

    init(point: (x: Int, y:Int)) {
        self.x = point.x
        self.y = point.y
    }

    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

Very nice! In case that you noticed self keyword and you want some explanation about that. Lets go the opposite way. Without self keyword the standard initialiser would look like:

init(x: Int, y: Int) {
    x = x
    y = y
}

Sorry, it's not possible to differentiate if x is the member property or the function's input parameter. By using self we declare that x and y are the instance's properties. Now its clear and compiler will not complain.

The point was a simple struct but the real beauty comes when we use simple structs to build more complex. For instance, we can define a struct to represent circle.

struct Circle {
    var center: Point
    var radius: Int
}

In this struct we use Point as member property. The instantiation of two new circles will look like:

var cir1 = Circle(center: p1, radius: 20.0)
var cir2 = Circle(center: Point(x: 1, y: 1), radius: 10.0)

In case that we want to access the properties of the Point which acts a centre for the circle se should use the dot syntax again:

let myX = cir2.center.x
let myY = cir2.center.y

Up to this point we haven't said anything about methods. Yes, structures can own functions which act as methods (like in classes). Every instance can employ its methods to do various calculations. For instance:

struct Circle {
    var center: Point
    var radius: Double

    func area() -> Double {
        return M_PI * pow(radius, 2)
    }
}

and we can use it like:

var cir2 = Circle(center: Point(x: 1, y: 1), radius: 10.0)
let circleArea = cir2.area() // 314.1592

Bonus!

In case that you have knowledge about properties in swift ( if not there is a properties 101 coming!), as you guess it, structs support computed properties as well. The area() of the last example could be easily implemented as such:

import Darwin // to get access to M_PI

struct Circle2 {
    var center: Point
    var radius: Double
    var area: Double {
        return M_PI * pow(radius, 2)
    }

}

var newCir = Circle2(center: Point(x: 1, y: 1), radius: 10.0)
let newCircleArea = newCir.area

Now it's your turn to experiment and get the hang of it.
If you want to use article's playground please be my guest!

Leave a Reply

Your email address will not be published. Required fields are marked *