Showing posts with label tips and tricks. Show all posts
Showing posts with label tips and tricks. Show all posts

Wednesday, November 23, 2016

Swift Tip: Understanding and using Closures

In Swift, closures are self-contained blocks of code that can be passed around and used in your code. Think of closures as anonymous functions in JavaScript, lambda expressions in C#, and blocks in C and Objective-C. Here is an example of closure in action in Swift:

        let alertController = UIAlertController(
            title: "Hello!",
            message: "Hello, World!",
            preferredStyle: UIAlertControllerStyle.alert)
        
        let okAction = UIAlertAction(
            title: "OK",
            style: UIAlertActionStyle.default) {
                (action) -> Void in
                print("Tapped on OK")
        }
        
        alertController.addAction(okAction)
        self.present(alertController,

                     animated: true, completion: nil)

In the above code snippet, when the OK button in the alert is tapped, you handle the action using a closure:

        {
                (action) -> Void in
                print("Tapped on OK")
        }

This closure takes in a single parameter - action, and does not return any value (Void). The body of the closure is a single statement that prints a string to the Output window. You can of course have more than one statement in the body of the closure. This works just like a usual function without the func keyword and the function name.

Besides this example, what are the real advantages of closures? Let's consider the classic example of the bubble sort:

    func bubbleSort(items:inout [Int])  {
        for j in 0 ..< items.count-1 {
            var swapped = false
            for i in 0 ..< items.count-1-j {
                if (items[i] > items[i+1]) {
                    let temp=items[i+1]
                    items[i+1]=items[i]
                    items[i]=temp
                    swapped=true
                }
            }
            if !swapped {
                break
            }
        }

    }

The above code snippet contains a function that takes in an array and then performs a bubble sort on it:

        var numbers = [5,2,8,7,9,4,3,1]
        bubbleSort(items: &numbers)

        print (numbers) // [1, 2, 3, 4, 5, 7, 8, 9]

There are two potential disadvantages with this implementation:

  • What happens if you want to sort non-integer values, such as string, doubles, etc? You need to rewrite the code to sort different data types. To solve this, you can use generics
  • What happens if you want to sort the values in descending order? You need to rewrite the code to perform the appropriate logic for swapping. And what happens if you have different criteria to determine the sort order for different data types? 

A better approach would be to rewrite the bubbleSort() function using a closure so that the caller of this method can provide its own implementation for the sort order. The rewritten function would look like this:

    func bubbleSort(items:inout [T],
        compareFunction:(T, T) -> Bool)  {
        for j in 0 ..< items.count-1 {
            var swapped = false
            for i in 0 ..< items.count-1-j {
                //---if the two numbers need to be swapped---
                if compareFunction(items[i],items[i+1]) {
                    let temp=items[i+1]
                    items[i+1]=items[i]
                    items[i]=temp
                    swapped=true
                }
            }
            if !swapped {
                break
            }
        }

    }

Observe that:

  • The function now has a second parameter (compareFunction:) of function type (T,T) -> Bool where T is a generic type. Caller of this function are expected to pass in a closure with two input parameters and return a Bool result.
  • Within the bubbleSort() function, it will call the closure passed into it and use its result to determine if a variable swap is needed.
To use the rewritten bubbleSort()function, you can call it like this:

        var numbers = [5,2,8,7,9,4,3,1]
        bubbleSort(items: &numbers,
                   compareFunction: {
                (num1:Int, num2:Int) -> Bool in
                    //--if num1 > num2, need to swap--
                    return num1 > num2
        })

        print (numbers) // [1, 2, 3, 4, 5, 7, 8, 9]

Note the closure highlighted in bold. In essence, you are passing in a function with two parameters. This function will return a true if the first number is greater than the second number. Essentially, you are sorting the numbers in ascending order. If you want to sort the numbers in descending order, simply change the comparison operator to <:

        var numbers = [5,2,8,7,9,4,3,1]
        bubbleSort(items: &numbers,
                   compareFunction: {
                (num1:Int, num2:Int) -> Bool in
                    //--if num1 > num2, need to swap--
                    return num1 < num2
        })

        print (numbers) // [9, 8, 7, 5, 4, 3, 2, 1]

The real advantage of using closure if when you need to sort strings in your own custom order. For example, you have an array of strings like this:

        var names = ["xxx","yy","z"]

To sort the strings based on string length, you can specify your closure like this:

        bubbleSort(items: &names,
                   compareFunction: {
                    (name1:String, name2:String) -> Bool in
                    //--if length of name1 > length of name2, need to swap--
                    return name1.characters.count > name2.characters.count
        })

        print (names) // ["z", "yy", "xxx"]

For purist, the above code snippet can be rewritten like this:
        
        bubbleSort(items: &names) {
            (name1, name2) -> Bool in
            name1.characters.count > name2.characters.count
        }

        print (names)

How cool is that. Hopefully, this posting can help you better understand and appreciate closures!

Tuesday, November 22, 2016

C# Tip - Using the async and await keywords for asynchronous programming

In C#, you can use the async and await keywords for asynchronous programming (such as fetching data from a network, or saving/loading data from files). To understand how to use these 2 keywords, consider the following example:

    async Task DownloadFromWebAsync()
    {
        HttpClient client = new HttpClient();
        Task getStringAsyncTask = 
            client.GetStringAsync("http://www.google.com");
        string content = await getStringAsyncTask;         

        // control is returned to the caller 
        // of the DownloadFromWebAsync() method 
        // and resumed after getStringAsyncTask 
        // is completed    

        return content;
    } 

In the above DownloadFromWebAsync() method , it is first of all prefixed with the async keyword, which indicates that this method contains an asynchronous operation. This method returns a Task result. This represents an asynchronous operation that returns a result of type string:

    async Task DownloadFromWebAsync()

Within this method, we use the HttpClient class to help us connect to the Web:

        HttpClient client = new HttpClient();

In particular, the GetStringAsync() method connects to the specified URL and returns the content of the URL. It returns an object of type Task:

        Task getStringAsyncTask = 
            client.GetStringAsync("http://www.google.com");

Because the GetStringAsync() method could potentially take a long time, and so you need to run it asynchronously. This is achieved by using the await keyword:

        string content = await getStringAsyncTask;

At this point, the GetStringAsync() method will proceed to download the specified URL and control will return to the caller of the DownloadFromWebAsync() method. All statements after this line will only be executed after the GetStringAsync() method returns.

When the GetStringAsync() method returns, the result is passed to content, and the DownloadFromWebAsync() method will now return a string.

To call the DownloadFromWebAsync() method, you would need to use the await keyword. Also, the method from which you are calling the DownloadFromWebAsync() method must also be prefixed with the async keyword, like this:

    private async void button1_Click(object sender, EventArgs e)
    {
        string content = await DownloadFromWebAsync();
    }

Note that the 2 statements:

    Task getStringAsyncTask = 
        client.GetStringAsync("http://www.google.com");
    string content = await getStringAsyncTask;         

Can also be rewritten as:

    string content = await      
        client.GetStringAsync("http://www.google.com");

I hope this simple example makes it easier for you to understand how to use the async and await keywords.

Saturday, November 19, 2016

Swift Tip - Using the guard statement

Very often, in your app you need to check if multiple variables are non-nil before you can perform some processing. For example, the following example shows that you can use the if statement to verify that both the credit card no. and expiry date is non-nil before you validate the credit card:

    func validatePayment(creditCardNo:String?, expiry:String?){
        if let cc = creditCardNo {
            if let exp = expiry {
                print("Validating credit card...")
                //...
                return
            }
        }
        print("Missing Credit Card No. or Expiry Date")

    }

However, the nesting of multiple if statements makes your code really unwieldy. A better way is to use the guard statement, like this:

    func validatePayment(creditCardNo:String?, expiry:String?){
        guard let cc = creditCardNo, let exp = expiry
        else {
            print("Missing Credit Card No. or Expiry Date")
            return
        }
        //---validate credit card---
        print("Validating credit card...")

    }

The guard statement ensures that both statements (let cc = creditCardNo and let exp = expiry) are true; else it will execute the else block.

The following shows the output of the function with the following combinations of arguments:

        //---Missing Credit Card No. or Expiry Date---
        validatePayment(creditCardNo: nil, expiry: "11/21")
        validatePayment(creditCardNo: "1234567890123456", expiry: nil)
        validatePayment(creditCardNo: nil, expiry: nil)
        
        //---Validating credit card...---

        validatePayment(creditCardNo: "1234567890123456", expiry: "11/21")

Swift Tip - Extensions

Extensions allow you to extend the functionality of an existing class, structure, enumeration, or protocol.  Here is an useful example:

extension Int {
    var isPerfectSquare:Bool {
        let sr = sqrt(Double(self))
        return ((Int(sr) * Int(sr)) == self)
    }

}

The above isPerfectSquare() function extends the Int class. You can call it to check if a number is a perfect square, like this:

        print(25.isPerfectSquare//---true---
        print(26.isPerfectSquare//---false---
        print(27.isPerfectSquare//---false---
        print(36.isPerfectSquare//---true---

Monday, September 28, 2015

Swift: Type Casting

This tips and tricks explains how to perform upcasting and downcasting in Swift, using the as, as!, and as? keywords.

Keywords

Swift 2.0, type casting, as, as!, as?

Solution

Upcasting using as

Upcasting happens when you are trying to cast from a derived class to a base class. This will always succeed. The following is an example using the as keyword to perform upcasting:

        let btn = UIButton()
        let view = btn as UIView

The as keyword can also be used for literal casting:

        let strNum1 = 2.4 as Float
        let strNum2 = 2.4 as Int

Downcasting using as?

Downcasting happens when you are trying to cast from a base class to a derived class. This may not always succeed.

Consider the following code snippet:

    @IBAction func btnClicked(sender: AnyObject) {
    }

In this action for a Button view, you have an argument named sender of type AnyObject. If you want to cast this to a UIButton, you may attempt to use the as keyword:

    @IBAction func btnClicked(sender: AnyObject) {
        let btn = sender as UIButton
    }

However, the compiler will flag this as an error as the type casting may fail. Instead, you have to use as? keyword to perform a downcast, like this:

    @IBAction func btnClicked(sender: AnyObject) {
        //---downcasting---
        let btn = sender as? UIButton
        print(btn?.titleLabel?.text)
    }

The as? keyword tries to perform a downcast, and returns a value of the specified type if it succeeds, or nil if it fails. Hence, the result of the above casting is a UIButton? (optional). To use the btn constant, you need to unwrap it using the ? ( or !) operator.

A safer way to deal with downcasting is to wrap it using the if let statement, like this:

    @IBAction func btnClicked(sender: AnyObject) {
        //---downcasting---
        if let btn = sender as? UIButton {
           //---casting succeeds---  
           print(btn.titleLabel?.text)        
        } else {
           //---casting failed---           
        }
    }

Notice that using the if let statement you now don’t have to unwrap the btn constant as it is now a UIButton and not UIButton?.

Downcasting using as!

If you are very sure that the casting will always succeed, you can use the as! keyword, like this:

    @IBAction func btnClicked(sender: AnyObject) {
        let btn = sender as! UIButton
        print(btn.titleLabel?.text)       
     }

The result of the casting is a value of type UIButton. However, if you are not careful, and the casting fails, it will crash your app:

    @IBAction func btnClicked(sender: AnyObject) {
        //---casting will fail and your app will crash!---
        let tableView = sender as! UITableView       
     }

When using the as! keyword, you can also specify the destination type to be an optional, consider the following:

        var dict = [Int:Any]()
        dict[1] = "Gold"
        dict[2] = "Silver"
        dict[3] = "Bronze"
       
        print(dict[1] as! String)  //---Gold---
        print(dict[1] as! String?) //---Optional("Gold")---


The last statement converts the specified item in the dictionary to a String? (optional).