Tuples, Enums and Protocols in Swift

Tuples in Swift allows user to assign group of values to a variable, constant and even return parameter of a function. In the below example, a employee constant is assigned Int and String values. And to access these parameters, we need to use .0 and .1

let employee = (103, “Deepak”)
employee.0
employee.1

Now let us say you want to assign proper name for these parameters so that you could access these values using those names instead of 0 and 1.

let employee = (id:103, name:“Deepak”)
employee.id
employee.name

Here id and name are parameter names provided for employee id and employee name. You can also declare the data types for the tuple values like Int and String

let employee:(id:Int, name:String = (102, “Deepak”)
employee.id
employee.name

Tuples and switch cases are powerful combination, look at an example below where Tuple has been used with switch cases. The _ is used for matching any values.

let employee:(id:Int, name:String) = (102, “Deepak”)
switch (employee) {
	case (103…105,_):
		println(“developer”)
	case (106…108,_):
		println(“tester”)
	case (_,“Deepak”):
		println(“CEO”)
	default:
		println(“Contractor”)
}

Enums

Enum in Swift allows users to group related values to a single data type. Swift enum has lot of new features compared to its predecessor Objective-C. Let us see this with an example enum type for all Months in a year.

enum Months {
	case January, February, March, April, May, June, July, August, September, October, 	November, December
}

enum Month {
	case January, February, March, April, May, June, July, August, September, October, November, December
}

Now you can define a variable or a constant of type month as shown below.

let currentMonth = Month.May

And variable or constant is declared with the data type then you can use the short form.

let currentMonth:Month = .May

Enum with Raw Value

Enum in Swift can be assigned a RawValue when declaring and the value can be of any data type. Let us day you want to specify the String value of each Month

enum Month: String {
case January = “January”, February = “February”, March = “March”, April = “April”, May = “May”, June = “June”, July = “July”, August = “August”, September = “September”, October = “October”, November = “November”, December = “December”
}

The RawValue can be printed by accessing .rawValue on the enum variable or constant.

let currentMonth:Month = .May
currentMonth.rawValue

Enum with Associated Value

Same like RawValue, enum can also have associated value and of data type.

enum Month {
	case January(String), February(String), March(String), April(String), May(String), June(String), July(String), August(String), September(String), October(String), November(String), December(String)
}

let currentMonth:Month = .May(“Summer Vacation”)

switch currentMonth {
	case .May(let message):
		println(message)
	default:
		println(“No Values”)
}

In the above example, Month enum values are declared with an associated value of data type String. And while assign the enum value the associated value is also provided to the currentMonth constant. Using the switch the associated value is retrieved.

Enum can have member function

Enum in Swift can also have member function. In the below example code, we have declared the Month enum with rawValue of type Int. Now add a member function to calculate the number of months left from the currently assigned value.

enum Month: Int {
	case January = 1, February, March, April, May, June, July, August, September, October, November, December func monthsLeftForYearEnd() -> Int {
	return Month.December.rawValue - self.rawValue
	}
}

let month: Month = .May
month.monthsLeftForYearEnd()

Constant month is assigned a enum value of .May and you can find out the number of months left for the year end by accessing the monthsLeftForYearEnd.

Enum can have Initialiser

Swift’s enum can have initialiser too where you can set the default enum value or do some initial processing. If you add init function as shown below, the default enum value will be set to July.

enum Month: Int {
	case January = 1, February, March, April, May, June, July, August, September, October, November, December
	init() {
		self = .July
	}

	func monthsLeftForYearEnd() -> Int {
		return Month.December.rawValue - self.rawValue
	}
}

let month = Month()
month.monthsLeftForYearEnd()

Protocols

Protocol in Swift defines the contract for a class or struct. This is similar to the interface in other languages like java. Protocol only defines the member function or variables and the actual implementation should be done in the conforming class or struct. Protocol can be be useful in the following ways

  • To add common behaviour across related or unrelated classes.
  • Supports in the implementation of delegation pattern

Let us see a typical example of protocol in Swift where we defining a Protocol called LivingThings with one method eat.

protocol LivingThings {
func eat() -> String
}

Any class or struct conforming to this Protocol should add implementation to eat method. In the below code example, we have got two classes Animal and Human which conform to LivingThings. implementation for the eat method has been added to both the classes.

class Animal: LivingThings {
	func eat() -> String {
		return “Animal Food"
	}
}

class Human: LivingThings {
	func eat() -> String {
		return "Human Food"
	}
}

let john = Human()
john.eat()

let cat = Animal()
cat.eat()

If a class conforming to a Protocol does not implement the required methods then you will find error message “error: type ‘Human’ does not conform to protocol ‘LivingThings’”

Protocol with Optional Methods

In Swift, Protocol with optional method can be defined by specifying the optional before the method definition and adding @objc keyword before protocol. Listed below is an example with Speakable protocol that has an optional method speak

protocol LivingThings {
	func eat() -> String
	}

	@objc protocol Speakable {
		optional func speak() -> String
	}

class Human: LivingThings, Speakable {
	func eat() -> String {
		return "Human Food"
	}

	func speak() -> String {
		return "Human can Speak"
	}
}

let john = Human()
john.eat()
john.speak()

Protocol and Delegation Pattern

A delegate pattern is used when you want a class to act on behalf of another class or for a callback mechanism. In the below code example we have defined a protocol (ImportDataDelegate) with two methods startImport and finishedImport. The DataImport class conforms to this Protocol and adds implementation to these methods. The DemoImport class acts on behalf of DataImport class by declaring a variable delegate of type ImportDataDelegate.

protocol ImportDataDelegate {
	func startImport()
	func finishedImport()
}

class DataImport: ImportDataDelegate {
	func startImport() {
		println("Import started")
	}

	func finishedImport() {
		println("Import finished")
	}
}

class DemoImport {
	var delegate: ImportDataDelegate?

	func startProcess() {
		delegate?.startImport()
		println("Doing some work ...")
		delegate?.finishedImport()
	}
}

This is how you pass the DataImport class to delegate variable of the DemoImport.

let demoImport = DemoImport()
demoImport.delegate = DataImport()
demoImport.startProcess()
In Category: Apple, Develop, 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 0 Comments
No comments yet. Be the first.

Leave a Comment