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.
[code language=”swift”]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()
[/code]
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.
Similarly the below code create a Square class
[code language=”swift”]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()
[/code]
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
[code language=”swift”]class Shape {
var name: String = ””
func area() -> Double {
return 0
}
func draw() -> String {
return “Draw a \(name) with area \(area()) “
}
}
[/code]
Sub Class – Square
[code language=”swift”]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()
[/code]
Sub Class – Rectangle
[code language=”swift”]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()
[/code]
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.
[code language=”swift”]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()
[/code]
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
[code language=”swift”]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()[/code]
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.
[code language=”swift”]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[/code]
lazy Property
Swift also provides lazy property whose value is assigned when the user access the property.
[code language=”swift”]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[/code]
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.
[code language=”swift”]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
[/code]
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.
[code language=”swift”]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")
}
}[/code]
Download the playground file from github (Classes and Struct)