In this part we will talk about Optional chaining, Casting, Extensions, Protocols, Generics and Operator overloading

Optional Chaining

From "The Swift Programming Language"

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil."

Similar to objc message to nil
It is similar to force unwrap, however if the var is not assigned instead of crashing it will return nil

var someVal:Test?

//Force unwrap will crash since someVal is nil
someVal!.var1

//Optional chaining will return nil
someVal?.var1

Testing for success

var someVal:Test?
if let val = someVal?.var1 {
  println(val)
}

Note: multiple level of optional properties (or methods) can be chained

a.somevalue?.hasValue.someOtherValue?.etc

When you do an optional chaining the returned value will be optional even if it wasn't optional at declaration

//nonOptionalProperty:  is defined as nonOptionalProperty: Int
//someValue is defined as someValue: Int?
var x = a.someValue?.nonOptionalProperty

//x now is optional x: Int?
x! //to access it unwrap or bind to an if statement

Casting

Check or convert the type of an instance

Checking type
var isInt = x is Int //isInt is a Bool
Downcasting

Casting from a super class to a subclass

var superC = SuperClass()
var subC = x as SubClass

as will crash if the cast cannot be made, as? will return an optional instance and it will not crash

Casting from Any to AnyObject

AnyObject can contain any class or function, Any can contain any class

Nested Types

Declare a Type inside another Type

class Test {
  enum TestEnum {
    case T1, T2, T3
  }
}

var e = Test.TestEnum.T1

Extensions

Adding new functionality to existing classes without subclassing them, similar to objc categories

extension Test {
}

What can be added:

  • computed properties
  • subscripts
  • Methods
  • nested types

What cannot be added:

  • Stored properties
  • Observer to existing properties

Protocols

Defines a blue print of methods and properties that should be implemented by any class that conform to the protocol.

protocol TestProtocol {
  //Required property
  var prop: Int { get set }
  //Required method
  func random() -> Double
}

//Conforming
class Test: TestProtocol {
}

var t = Test()
t is TestProtocol //test

For protocol to be exported to objc write @objc before its declaration

@objc protocol TestProtocol { }
Optional protocol requirements

@optional is added before the requirement to make it optional, note that only @objc protocol can have optional requirements

@objc protocol ButtonDelegate {
  func buttonTapped ()
  @optional func f1()
}

var delegate: ButtonDelegate?
self.delegate!.f1?() //Called with optional 

Generics

Generic code allow to write methods and classes that work on every type, Generic makes passing different types to the same function work with maintaing the type safety

Generic Functions

Use generics by adding a placeholder type in the function declaration <T> and use it inside the arguments,
<Type> tells swift that Type is a placeholder and not an actual type

func test<TYPE>(a: TYPE) {
  println(a)
}
Generic Types

Swift enable you to create generic types that work with any Type, such as Array or Dictionary

struct Stack<T> {
  var data = T[]()

  mutating func push(val: T) {
    data.append(val)
  }

  mutating func pop () -> T {
    return data.removeLast()
  }
}

var a: Stack<Int> = Stack()
a.push(10)

The T in the above example will be treated as Int

Type Constraints

Swift enable you to enforce constraints on types to be subclasses of some super type or to conform to a protocol

class Stack<T: Class, S: Protocol> {}

Associated Types

Any protocol could specify an associated type with typealias, This allows the protocol to defer the Type selection to the class that will conform to this protocol.

protocol Prot {
  //Leave the decision of the type to the conforming
  typealias MyType
  func add(i: MyType)
}

class Class : Prot {
  //MyType is an Int
  typealias MyType = Int
  func add(i: My      Type) { }
}

//Or leave swift to infer what MyType is    
class Class : Prot {
  func add(i: Int) { }
}
Where Clauses

Where helps add a constraint on Types and Associated types of a Protocol

protocol Prot {
  typealias ItemType1
  typealias ItemType2
}

class TClass <T: Prot where T.ItemType1 == Int, T.ItemType2 : Equatable> { }

class TClass accepts any type that conform to protocol Prot and have an ItemType1 of Int and ItemType2 is a subclass (or conforms) to Equatable

Operator overloading

Swift allow you to provide custom behaviour for operators that are tied to your class

Consider this struct

struct Point {
  var x,y: Int
}

Operator types:

  • @infix a binary operator, take two argument such as + in 1 + 1
  • @prefix a unary operator, take one argument such as ++ in ++i
  • @postfix a unary operator, take one argument such as ++ in i++
  • @assignment a binary operator, takes two argument, the first one is inout, such as += in p += 1 @assignment assigns the result of the operation to the left hand

Syntax for operator overloading

operator_type func operator (args) -> ret {}
//example
@infix func ++ (..) {}
Infix operator

infix operator are binary operators that come in the middle of the operation

//Adding this method will make + available on all points
@infix func + (p1 : Point,p2: Point) -> Point{
  return Point(x: p1.x + p2.x, y: p1.y + p2.y)
}

//p1 and p2 are points
var p3 = p1 + p2

Equivalence == is an infix operator too

@infix func == (inout p1: Point, p2: Point) -> Bool{
  return true
}
Postfix and prefix operator

Postfix and prefix are unary operators that come after or before the instance

//Does not return anything
//var p = ++p1 is not valid
@prefix func ++ (inout p1: Point){
  p1.x++; p1.y++
}

//Returns point
//var p = ++p1 is valid
@prefix func ++ (inout p1: Point) -> Point{
  p1.x++; p1.y++
}
Assignment Operators

Assignment Operators are binary like += -= etc..., you should use @assignment with them

@assignment func += (inout p1: Point, p2: Point) {
  p1 = p1 + p2
}
Custom Operators

You can define any of these operators / = - + * % < > ! & | ^ . ~ or any of their combinations

//First define the new operator, and specify its type
//prefix, infix or postfix
operator prefix +*+ {} //prefix are Unary

//Overload the operator
operator prefix +*+ {}
@prefix func +*+ (p1: Point) -> String {
  return p1.toString()
}

//p is a point, x is a string
var x = +*+p