Class and Struct in Swift

Download the playground file from github (Classes and Struct)

Class

A class is a blue print for a real-word entity such Player, Person etc. and it is used for creating objects. Class can have properties to store values and methods to add behaviour. Let us see this with an example class called Rectangle which has some properties and two methods for calculating area and for drawing a rectangle.

class Rectangle {

var name:String = ””
var length:Double = 0
var breadth:Double = 0

	func area() -> Double {
		return length * breadth
	}

	func draw() -> String {
		return “Draw rectangle with area \(area()) “
	}
}

let rect = Rectangle()

rect.length = 20
rect.breadth = 10
rect.draw()

 

In the above example, we have a class named Rectangle, with name, length and breadth as properties, area and draw are functions. rect is a instance variable or object of Rectangle class. On setting the length and breadth and calling draw function should provide the following output in Playground.

201505101309.jpg

Similarly the below code create a Square class

class Square {

var name:String = ””
var length:Double = 0

	func area() -> Double {
		return length * length
	}

	func draw() -> String {
		return “Draw a square with area \(area()) “
	}
}

let squr = Square()
squr.length = 20
squr.draw()

 

Now instead of repeating property and functions in each classes let us use class inheritance to simplify these classes.

Class Inheritance

Let us create a parent class called Shape and its properties and functions will be inherited by Sub Classes Rectangle and Square.

Parent Class – Shape

class Shape {
var name: String = ””

	func area() -> Double {
		return 0
	}

	func draw() -> String {
		return “Draw a \(name) with area \(area()) “
	}
}

 

Sub Class – Square

class Square:Shape {

var length: Double = 0
	override func area() -> Double {
		return length * length
	}
}

let squr = Square()
squr.name = “My Square”
squr.length = 5
squr.draw()

 

Sub Class – Rectangle

class Rectangle:Shape {
	var length: Double = 0
	var breadth: Double = 0

	override func area() -> Double {
		return length * breadth
	}
}

let rect = Rectangle()
rect.name = “My Rectangle”
rect.length = 5
rect.breadth = 10
rect.draw()

 

Parent class Shape has been created with name property and functions area and draw. The child class Square and Rectangle will inherit these property and methods. Apart from the parent class property, Square can have its own property length and Rectangle has length and breadth. The parent class area function has been overridden by Square and Rectangle class to calculate corresponding areas. Now if you want add one more Shape such as Triangle, Circle etc the new class has to inherit Parent class (Shape) and add its own property and methods (or override methods).

Initialisers

Initialisers in Class and Struct are used for setting the default values for properties and for doing some initial setup. Here is a typical example of initialiser in a Class where the name property is initialised at the time of creating an instance.

class Shape {

var name: String
	init(name: String) {
		self.name = name
	}

	func area() -> Double {
		return 0
	}

	func draw() -> String {
		return “Draw a \(name) with area \(area()) “
	}
}

class Square: Shape {
	var length: Double = 0

	init() {
		super.init(name: “MySquare”)
	}

	override func area() -> Double {
		return length * length
	}

	override func draw() -> String {
		return “Draw a \(name) with area \(area()) “
	}
}

let squr = Square()
squr.length = 10
squr.draw()

 

The sub class Square initialises the name property in init function by calling super.init and after creating the Square instance you need to pass value for the length property.

Designated and Convenience Initialisers

Initialiser which initialises all the properties in a class is known as designated initialiser. A convenience initialiser will initialise only selected properties and in turn will call the designated initialiser in init function. Listed below is a Square class with designated initialiser and convenience initialiser

class Shape {
	var name: String
	init(name: String) {
		self.name = name
	}

	func area() -> Double {
		return 0
	}

	func draw() -> String {
		return “Draw a \(name) with area \(area()) “
	}
}

class Square: Shape {
	var length: Double

	// Designated Initializer
	init(length:Double, name:String) {
		self.length = length
		super.init(name: name)
	}

	// Convenience Initializer
	convenience init(length: Double) {
		self.init(length:length, name:“MySquare”)
	}

	override func area() -> Double {
		return length * length
	}

	override func draw() -> String {
		return “Draw a \(name) with area \(area()) “
	}
}

let squr = Square(length: 10,name: “MySquare”)
squr.draw()

let squrNew = Square(length: 20)
squrNew.draw()

Computed Property

A property in swift can be used for performing operation at the time of assigning value. Here is an example, where the length of Square is computed based on assigned area.

class Sqaure {
	var length: Double = 0
	var area: Double {
		get {
			return length * length
		}

		set (newArea) {
			self.length = sqrt(newArea)
		}
	}
}

let square = Sqaure()
square.area = 4 // set call
square.length = 6
square.area // get call

lazy Property

Swift also provides lazy property whose value is assigned when the user access the property.

class Person {
	var name: String
	init (name: String) {
		self.name = name
	}

	lazy var message: String = self.getMessage()

	func getMessage() -> String {
		return “Hello \(name)”
	}
}

let person = Person(name: “Jason”)
person.message

in the above code example, the value for message property is not set at the initialisation and will be set only when call the message property in person object. Some typical where you could due lazy property is when retrieving values from performance intensify operation such as Network or Read/Write.

Property Observers

Swift provides two property observers, willSet and didSet. These methods gets triggered when a value is about to be set for a property or after setting the property.

class Square {
	var length: Double = 0 {
		willSet(newLength) {
			println("Setting length \(self.length) to new length \(newLength)")
		}

		didSet {
			println(“Length is modified - do some action here”)
		}
	}

	var area: Double {
		get {
			return length * length
		}

		set (newArea) {
			self.length = sqrt(newArea)
		}
	}
}

let square = Square()
square.length = -6
square.area

 

In the above example, Square class length property has a willSet and didSet observers.

Struct

Struct and Class can both have properties, methods, protocols, extensions and initialisers. You can use struct to hold simple values and when you want to pass around those across your program. A typical example would be using Struct to hold values from a web service call. Listed below is a web service call that we had seen earlier in Xcode and Playground overview. In the below code example you should find a GeoDetails struct for storing the values returned from geoip web service.

struct GeoDetails {
	var country: String
	var ip: String
	var isp: String
	var latitude: Double
	var longitude: Double
	var timeZone: String
	
	init(country: String, ip: String, isp: String, latitude:Double, longitude:Double, 		timeZone:String) {
	self.country = country
	self.ip = ip
	self.isp = isp
	self.latitude = latitude
	self.longitude = longitude
	self.timeZone = timeZone
	}

	func description() -> String {
		return “Country ” + self.country + “, ip ” + self.ip + “, isp ” + self.isp + “, 	latitude \(self.latitude), longitude \(self.longitude) “
	}
}

var geoDetails: GeoDetails?
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

let url = NSURL(string: “http://www.telize.com/geoip”)

NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
	if error == nil {
		var error:NSError?
		if let result = data {
			if let dict = NSJSONSerialization.JSONObjectWithData(result, options: 	NSJSONReadingOptions.AllowFragments, error: &error) as? NSDictionary {
				geoDetails = GeoDetails(country: dict[“country”] as! String, ip: dict[“ip”] as! String, isp: dict[“isp”] as! String, latitude: dict[“latitude”] as! Double, longitude: 	dict[“longitude”] as! Double, timeZone: dict[“timezone”] as! String)
				println(geoDetails?.description())
	} else {
	println("Error")
	}
}

Download the playground file from github (Classes and Struct)

In Category: Apple, Programming

Ravi Shankar

A polyglot software developer and now exploring Swift and iOS development. If you would like to learn from me then check out services page.

Show 3 Comments
  • Isuru December 14, 2014, 6:00 pm

    I think the last image is missing in the tutorial.

  • Samsudeen Ariff March 1, 2016, 1:19 pm

    Very helpful tutorial for beginners, just noticed that functions are having -> probably an editor issue.

    • Ravi Shankar March 2, 2016, 2:42 pm

      Thanks Sam. Yes it is editor issue will fix it.

      Regards,
      Ravi

Leave a Comment