Swift Overview

Consideration on Initializers (Review on Swift3):


In swift we have two kind of initializer 1-Designated 2-Convenience

ALl enum , struct and class can have initializer  if not provided system uses the default initializer

Structs can only have designated initializers, structs cannot have convenience initializers. 

Example for Enum:

enum Number {

   case One

   case Two

   case Three

   case Four

   case MoreThanFour

   init(number n: Int) {

if n == 1 { self = .One }

else if n == 2 { self = .Two }

else if n == 3 { self = .Three }

else if n == 4 { self = .Four }

else { self = .MoreThanFour }

   }

}

let x = Number(number: 3)

print(x)

// prints: "Three"


The main goal of initializer is to make sure all your properties are initialized when your class is instantiated 

There are a few rules that should be respected in relation with Designated and Convenience initializers in order to achive this goal


General Rule 

 +Any class have at least one designated init , default initializer is considered as designated

 +Designated initializers must(and this is the only option) call designated initializer from imediate superclass
  (if any).they cannot call convenience initializers = delegate UP

 +Convenience initializers must (and this is the only option) call another initializer from the same class ;It can be a
  designated or another convenience initializers = delegate across

 +At least one convenience initializers must call a designated initializers.

 

 As we mentioned the main goal is to initialize all properties so we have more rules:

Property Rule:

 +A designated initializer must initialize all its non-optional and non-inherited properties before calling its immediate superclass initializer

 +A designated initializer must modify or initialize inherited properties after immediate superclass have been initialized!

 +A Convenience initializer must call another initializer in the same class before modify/assigning any value to any stored properties

 +An initializer cannot reference instance (by using self) before initialization is completely done for that class!

 

A Failable Initializer is an initializer which initialization can fail, such as UIImage NSImage,....

Example:

  init?(name: String) {

        if name.isEmpty { return nil }

        self.name = name

    }



Protocol with optional methods:

Even this is not Swifty but to keep backward compatibility with Objective-C in which Optional method are perfectly legal! (don’t mess Optional method in Protocol with Optional variable in swift!!!!! An optional method In Protocol means implementation is not mandatory!)

As I mentioned using Optional Methods in protocol is Anti-Swift , as a Swift developer you should avoid it except in some cases you really need it, but there is some rules to be remind:

1)If you have an optional method , you must add  @objc attribute to declaration of protocol 

2)Swift struct or enum cannot adopt this protocol

3)Only class derived from NSObject can adopt it

(the reason why should be derived fro NSObject is that it’s an Objective-C concept)

@objc protocol myProtocol{

func(n:Int)->Int

optional func (m:Double)->Bool //

}

Important : protocol can only have computed properties and cannot have stored property


Consideration on SWIFT 2.2 :

Swift 2.2 released in March 2016 comes with new changes and features, many previous features have been dprecated meaning in next version Swift 3.0 ,They maybe definitely removed and no longer available , here I have a resume of those modifications:


  • Compile Time Swift version checking :


Now in Swift 2.2 One of the great improvement in Swift 2.2 is the ability to check Swift version in Compile Time rather than OS() checking in Run Time , now in Swift 2.2 It’s possible to check the current swift version with macro checker as :

#if swift(>=2.2)

    print("swift compiler version >=2.2")

#else

    print("swift compiler version <2.2")

#endif


the portion of code in the case of a compiler version other than the current one will be ignored completely by compiler!

However these macro style are nostalgic for many C++ developers!!!



  • C-Style Loop is dprecated :

for var i=0;i<10;i++ {

}

instead we use classic swift loop like:

for i in 0..<10 {

    print(i)

}


As ++ increament operator is deprecated the step increament can be performed as

for i in 0.stride(to: 10, by: 1){ //10 excluded

    print(i)

}


for i in 0.stride(through: 10, by: 1){ //10 included

    print(i)

}


  • Tuples Improved :

Now in Swift 2.2 operator == is overloaded by default for Tuples , in previous version many developers had to add an overload function, now no need anymore to overload this operator , notice there is a limit on argument, maximum argument allowed is 6! lets see two tuples as following:

let t1 = (val1:5,val2:6)

let t2 = (val3:5,val4:6)

if t1 == t2 {

    print("t1 is equal to t2”) 

} else{

     print("t1 is NOT equal to t2")

}

This code will print "t1 is equal to t2 in output , compiler doesnt’ care the label name for tuples



  • Debug macro information changed from C++ style to Swift style:

Debug information __FILE__, __LINE__, __COLUMN__, __FUNCTION__ changed
 to
#file,#line,#column,#function Example :

func powerOfTwo(x:Int)->Int{

    print(#function)

    return x*x

}

let y = powerOfTwo(2)



  • String format for Selectors are deprecated in Swift 2.2:

String format Selectors are deprecated , for example if we setup an observer for battery level changes generally we use the code below in a ControllerView:

NSNotificationCenter.defaultCenter().addObserver(self,selector: "batteryLevelChanged:",name: UIDeviceBatteryLevelDidChangeNotification,object: nil)

Now in Swift 2.2 we passing selector as a string is no longer authorized , instead we use:

NSNotificationCenter.defaultCenter().addObserver(self,selector: #selector(batteryLevelChanged),name: UIDeviceBatteryLevelDidChangeNotification,object: nil)

#selector is a macro to check and retrieve the correct selector name so if selector doesnt exist generate a compile error and hopefully It fix many issues related to incorrect typing!





Some basic consideration :

Using final :

In Swift similar to Android we have final word to indicate a non-modifiable variable , but this concept is a little bit  extended in several situation, when we talk about a final class it means we cannot subclass it , on the other hand when we declare a method as a final , it means we cannot override it , for a property the same way we cannot change it’s value

//final keyword can be used only from the class scop context , a member , a method,... there is no global scop except a class marked as final

//a final class cannot be subclassed
//a final method cannot be overriden



Value and Reference type :

In Swift like many other languages we have the concept of value type and reference type, value type keeps its own copy of data but reference is a reference to a shared data , a value type creation is in fact creation of a new zone of memory to hold data on the other hand reference is in fact keeping a reference to a single zone of memory (pointer) , so in term of memory more value type represents more memory usage.


Value type:

enum , struct , tuple , Array, String , Dictionnary 


Reference type:

class 


when using value type equal check operator == can be used to compare two types , and when using reference check operator is === 

For example when we reference a  class A as 

class A{

init(){

//initializing

}

}

let a = A()
var b = a

Both a and b are now pointing to a single shared object A , any attempt to modifying a property from each of them will impact both objects , however in a structure type , as a struct is a value type the result will be different:

struct A {

}

let a = A()
var b = a //a and b are two different value,changing a property from one of them doesn’t impact other one!

Notice : IOS expose a protocol xxx to let copy a referenced object in the case we need , any class derived from NSObject can perform an object copy instead of sharing reference , here is an example of this concept


class MyRecord : NSObject , NSCopying{

    var name : String

    var age : Int

    init(name:String,age:Int){

        self.name = name

        self.age = age

    }

    convenience override init(){

        self.init(name: "John",age: 29)

        

    }

    func copyWithZone(zone: NSZone) -> AnyObject {

        return MyRecord()

    }

    

    func printData(){

        print("\(self.name+String(age))")

    }

    func setRecName(name:String){

        self.name = name

    }

}


let a = MyRecord()

a.printData()

var b = a.copy()  // copy the class

b.setRecName("Paul")

b.printData() // print “Paul 29"

a.printData() // print “John 29



Computed properties :

In Swift Computed properties are getter/setter properties of a type, which purpose is to convert or compute their values to represent multiple form.A very simple example could be a Speed class which have two different properties one in KM/H and the second one in Mile/H   :


class Speed {

    var meterPerSecond : Double = 0

    var milePerHour : Double {

        set{

            self.meterPerSecond = (newValue*1.6)/3.6

        }

        get{

            return (self.meterPerSecond*3.6)/1.6

        }

    }

    

    var kmPerHour : Double {

        set{

            self.meterPerSecond = newValue/3.6

        }

        get{

            return (self.meterPerSecond*3.6)

        }

    }

}


let speed = Speed()


speed.kmPerHour = 100

print("\(speed.milePerHour)")

 As we see milePerHour and kmPerHour are the computed properties


Property Observer :

Similar to Computed properties , Property observers main purpose is to notify a listener from changes in Setter , we report the changes usually via keywords willSet and didSet  , as the names are pretty clear willSet is fired when the value is about changing , and didSet fires when the value is definitly changed.



protocol Reporter{

    func reportChanges(step:Double)

}

class PrintReport : Reporter{

    func reportChanges(step: Double) {

        print("speedStep = \(step)")

    }

}

class Speed {

    

    var meterPerSecond : Double=0

    var speedStep : Double = 0

    var report : PrintReport!

    //observer property

    var milePerHour : Double = 0{

        willSet{

            meterPerSecond = newValue*1/6/3.6

            print("newvalue=\(newValue)")

        }

        didSet {

           

            speedStep = abs(oldValue-self.milePerHour)

             report.reportChanges(speedStep)

        }

        

        

    }

    

   }


let speed = Speed()

speed.report = PrintReport()

for var mph = 40 ; mph<130 ; {

    speed.milePerHour = Double(mph)  // changes are reported via didSet

    mph = mph+10

}

Screen Shot 2016-03-29 at 12.25.01 AM


result as diagram in Playground:


Notice in Swift Property Observer is NOT called during the initialization , let’s analyse it by changing the codes like this:


class Speed {

    var meterPerSecond : Double=0

    var speedStep : Double = 0

    var report : PrintReport!

    init(mph:Double){

        self.milePerHour = mph

    }

    //observer property

    var milePerHour : Double{

        willSet{

            meterPerSecond = newValue*1/6/3.6

            print("newvalue=\(newValue)")

        }

        didSet {

           

            speedStep = abs(oldValue-self.milePerHour)

             report.reportChanges(speedStep)

        }

        

        

    }

    

   }


let speed = Speed(mph: 90) //NO print in output! when initialize 


Another thing to keep in mind is a lazy property cannot set any Observer because the lazy property is initialized only when caller, call it and there is absolutly no any initial values for such a property before calling and oldValue is not initialized


Mutating function on a value type :

As we have seen a value type like structures is by default an immutate value , meaning cannot change or modify properties on itself (the current instance),in order to be able to modify properties we use keyword “mutating” , let’s see in an example:

struct Record{

    var name:String

    var age:Int

    

   mutating func setRecord(name:String,age:Int){

        self.name = name

        self.age = age

    }

}

var record = Record(name: "John", age: 25)

record.setRecord("Paul",age:30)

print("\(record.age)”)


Subtle consideration  :


Function pointers in swift :

One of the exciting point about swift is the ability of getting reference to a method by just its name ( as poniter) developer call it "passing parameters before method name)

let see this class :


class Record {

    func getName()-> String {

     }


Now let's call getName as we usualy do

let record = Record()

let name  = record.getInfo("Alex")


Now Calling it by using a function pointer:


let record  = Record()

//get just a pointer, not calling , not argument provided and it's not static after all!

let getInfo = Record.getInfo 

now we call it:

getInfo(record)("Alex")

or simpler in just one line :

Record.getInfo(record)("Alex") 



Variadic parameters:

To avoid providing an array each time you are calling a function , use variadic

func insertRecords(names:String...){

}


then you call insert("Alex") or insert("Alex","Khosrov") ,.....



Difference between inout and variable parameters 

by default a parameter in a swift function is constant , to change the rule you either use inout or variable parameters.

func makeFormatedName(inout name:String,index:Int)->String{

name  =  name+String(index)

return name

}

var name = "Alex"

let result  = makeFormatedName(&name,1)

//result = name  = "Alex1"



with variable arguments

func makeFormatedName(var name:String,index:Int)->String{

name  =  name+String(index)

return name

}

var name = "Alex"

let result  = makeFormatedName(&name,1)

//result = "Alex1" but name  = "Alex"

in the case of inout after calling the externale provided variable get changed

but in the case of a variable argument it's not changing



typealias get functions more readable:

typealias is equivalent of typedef in C/c++ , suppose you are passing a function as parameters:

func getRecord(makeFormatedName:(String, Int) -> String)->Int{

 let result  =  makeFormatedName("Alex",10)

 return result

}


typealias makeFormatedName = (String, Int) -> String

func getRecord(format : makeFormatedName)->Int{

let result  =  format("Alex",10)

return result

}


Subtle consideration on Views :

Creation of View: There are two way to create or make a view , all views or widgets (Label,Button,....) are a subclass of UIView, and there are two constructors (initializers) 

for UIView :

  1. UIView(Frame:CGRect) 
  2. UIView(coder:NSCoder)

there are typically two way to create your view either by storyboard or completely by code ) , if your view is created entirely in storyboard you are given the second initializer , and if you create it by code you are given the first initializer

 © Xosrov 2016