Sunday, September 13, 2015

Arrays & Dictionaries

Unlike their ObjC counterparts, Arrays and Dictionaries in SWIFT are value types. As long as keys and values are not reference types, both arrays and dictionaries will stay on as value types

var itemsToBuy = ["Coffee":"200 gm", "Tea": "100 gm", "Hot Chocolate": "500 gm"]

for (index, value) in itemsToBuy.enumerate() {
    print("Item: \(index) + quantity: \(value)")
}

var copiedItemsToBuy = itemsToBuy
copiedItemsToBuy["Coffee"] = "100 gm"

With this change, its only copiedItemsToBuy has changed, items ToBuy, remains as it is, which is what copy by value means

Behavior of Arrays are slightly different
var items = ["books", "pens", "notebook"]

func printArray(items:[AnyObject]) {
    for (index, item) in items.enumerate() {
        print("Index: \(index), Value:\(item)")
    }
}

var copiedItems = items

Any changes done to copiedItems is reflected in "items", unless there is an addition or deletion of items. In short, unless there is change to the overall count of items contents are shared.

There were a few methods in the past that would work, but are no longer working
1. unshare
2. copy
3. compare and contrast addresses === & !==

May be those will get back to work sooner.

Saturday, September 12, 2015

Enumerations

Enumerations are no new additions to programming language. They have always been there from age old days. But what has changed in SWIFT's enumeration are somethings that we have taken for granted in the past. Like default constant values associated with enumeration values. In addition, handling range values (New in SWIFT), having function definitions and also initializing with init methods.

enum Rank {
    case One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack
    case Queen
    case King
    case Ace
    
    func rankDescription() -> String {
        switch self {
        case .One, .Two, .Three, .Four, .Five, .Six, .Seven, .Eight, .Nine, .Ten:
            return "Numbers"
        case .Jack:
            return "Jack"
        case .Queen:
            return "Queen"
        case .King:
            return "King"
        case .Ace:
            return "Ace"
        }
    }
}


enum Suit {
    case Hearts, Clubs, Diamonds, Spades
    case Others
    
    func suitDescription()->String {
        switch self {
        case Hearts:
            return "Heart of hearts"
        case Clubs:
            return "Beat the hell out of your enemy"
        case Diamonds:
            return "You are the richest of all"
        case Spades:
            return "You are the truest of all"
        case Others:
            return "Not sure, why you folks are here"
        }
    }
    
    func colorForCards()->String {
        switch self {
        case Hearts, Diamonds:
            return "Red"
        case Clubs, Spades, Others:
            return "Black"
        }
    }
}

let myCard = Suit.Diamonds
print("Card description: \(myCard.suitDescription())")
print("Card description: \(myCard.colorForCards())")



struct Card {
    var rank: Rank
    var suit: Suit
    func cardDescription() -> String {
        return "The rank is:\(rank.rankDescription()) and suit is: \(suit.suitDescription()) with color \(suit.colorForCards())"
    }
}
let threeOfSpades = Card(rank: .King, suit: .Diamonds)
print(threeOfSpades.cardDescription())

/*
* Use this to process response from remote service and invoke appropriate functions
*/
enum Response {
    case success(String, String)
    case Failure(String)
}

let successServerResponse = Response.success("http://www.google.com", "{searchResult:{[result1:virtusa, result2:something, result3:anotherthing]}}")
let failureServerResponse = Response.Failure("Failed to fetch any results")

func processResponse( response:Response) {
    switch(response) {
    case let .success(searchURL, searchResult):
        print("URL: \(searchURL) and response is: \(searchResult)")
    case let .Failure(error):
        print("Erorr is: \(error)")
    }
}

processResponse(successServerResponse)

let shoppingList = ["Shell for MacBook", "Wireless mouse", "Raspberry Pi - B"]
for item in shoppingList {
    print("Items to buy \(item)")

}

Friday, September 11, 2015

Functions in SWIFT

SWIFT has treated functions as first class members through out. But what do we mean by first-class members? The only way we can find it out is by trying it out.

We will be able to pass function as parameter to functions, use function in return statements. What does it buy you. Well of starters, it allows to inject functions based on various conditions, this way DRY principles are achieved. Better readability and code cohesion.

Here are some examples on the same

/*
* Having functions as first-class citizens
* Return a function. This can be a classic case for creational patterns in the application
*/

func addOne(var num:Int) -> Int {
    return ++num
}

func addTwo(num:Int) -> Int {
    return num + 2
}

func makeIncrementer( incrementerType:String) -> (Int -> Int) {
    switch(incrementerType) {
    case "Double":
        return addTwo
    default:
        return addOne
    }
}

var incrementer = makeIncrementer("single")
print("Value is: \(incrementer(10))")
incrementer = makeIncrementer("Double")

print("Value is: \(incrementer(10))")


/*
* Pass a function as a parameter
* This can be a classic case for validations
*/
func validNumber(num:Int) -> Bool {
    return (num > 100)
}

func hasAnyMatches(numbers:[Int], condition: Int -> Bool) {
    for num in numbers {
        if condition(num) {
            print("Matches the condition, valid number: \(num)")
        }
    }
}

hasAnyMatches([10, 110, 20, 120, 30, 130], condition: validNumber)
// Make anonymous function
hasAnyMatches([8, 13, 12, 10, 5, 3, 14, 16]) { (number:Int) -> Bool in
    return number%2 == 0
}

/*
* Functions with default parameters
* Finally we have an easeir way to handle default parameters
*/
func concatenateString(firstString:String, secondString:String, joiner:String = " ") -> String {
    return firstString + joiner + secondString
}

print(concatenateString("Hello", secondString: "World", joiner:"-"))
print(concatenateString("Hello", secondString: "World"))

/*
* calculate MEAN
*/
func meanForNumbers(sum:Int, count:Int) -> Int {
    return (sum/count)
}
/*
* Variadic parameters
*
*/
func meanForNumbers(mathFunction:(Int,Int)->Int, numbers:Int...) {
    var sum = 0
    for number in numbers {
        sum += number
    }
    let meanForNumbers = mathFunction(sum, numbers.count)
    print("Mean is: \(meanForNumbers)")
}

/*
* Creating function types
*/

func addTwoNumbers(num1:Int, num2:Int) -> Int {
    return (num1 + num2)
}

func multiplyTwoNumbers(num1:Int, num2:Int) -> Int {
    return (num1 * num2)
}

var mathFunction:(Int, Int) -> Int = addTwoNumbers
print("Sum of 2 numbers: \(mathFunction(11, 12))")
mathFunction = multiplyTwoNumbers
print("Product of 2 numbers: \(mathFunction(11, 12))")

/*
* It gets even better, with let. When we use "let", we do not need to pass
* on the type, as always is the case with "let". However the difference
* though is, you get to pass on parameter names. No complaints, anything
* to make the code more readable
*/
let myMathFunction1 = addTwoNumbers
print("Sum of 2 numbers: \(myMathFunction1(11, num2: 12))")
let myMathFunction2 = multiplyTwoNumbers

print("Product of 2 numbers: \(myMathFunction2(11, num2: 12))")

/*
* Nesting functions. With functions being trated as first-class citizens
* we can now nest one function into another, like containment.
*/

func chooseStepFunction(backwards:Bool)->()-> Int {
    var currentStep: Int = 10
    let maxSteps: Int = 100
    let minSteps: Int = 0
    
    func stepForward() -> Int {
        return currentStep + 1
    }
    
    func stepBackward() -> Int {
        return currentStep - 1
    }
    
    return backwards ? stepBackward : stepForward
}

var myNextStepBack = chooseStepFunction(true)
print("My next step is: \(myNextStepBack())")
//Output: My next step is: 9

var myNextStepForward = chooseStepFunction(false)
print("My next step is: \(myNextStepForward())")

//Output: My next step is: 11

Switch-Case in SWIFT 2.0

There have been major changes with switch...case conditions in SWIFT. With each version upgrade, things have gotten better and is at best in 2.0. Here are some simple samples of how SWITCH statements can be used

// Switch statement varieties in SWIFT 2.0
/*
* Switch statement with string and string conditions in cases
*/
let vegetable = "Baby  cucumber"
switch vegetable {
    case "celery":
        let vegetablecomment = "Add some rasinis, it will tase good"
    case "cucumber", "watercress":
        let vegetablecomment = "That would make a good tea sandwich"
    case let x where x.hasSuffix("pepper"):
        let vegetablecomment = "Is it spicy?"
    case let x where x.hasPrefix("Baby"):
        let vegetableComment = "mmmmmm, yummy..."
    default:
        let vegetablecomment="Not really"
}

/*
* Where clause makes it easy to process switch
*/
let myCirclePoint = (1, -1)
switch myCirclePoint {
case let(x, y) where x == y:
    print("It's a dot")
case let(x, y) where x == -y:
    print("It's a line towards left")
case let(x,y):
    print("Some arbitrary point in circle")
}

/*
* Switch statement with ranges in cases
*/
let numberCount = 100
switch numberCount {
case 1...99:
    print("Value less than 100")
case 100...199:
    print("Value less than 200")
default:
    print("Others")
}

/*
* Switch statement with tuples cases and ranges
* Isn't this awesome? Switch cases have never made code more easy.
* This makes code like error handlong so much more easy!!!
*/
let myHeight = (6, 11)
switch myHeight {
case (4, 1...11):
    print("Shortest")
case (5, 1...11):
    print("Tall")
case (6, _):
    print("Really tall")
case (_, 1...11):
    print("Are you human?")
default:
    print("Never executed, wish could get rid of it....")
}
}