Showing posts with label swift. Show all posts
Showing posts with label swift. 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!

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---

Sunday, July 31, 2016

Swift Cheat Sheets updated for Swift 3.0

My Swift Cheat Sheets are now updated for Swift 3.0. To try out Swift 3.0, you would need Xcode 8 (beta 3 at the time of writing). You can download the cheat sheets by clicking on the images below.

Sunday, July 03, 2016

Mobile Development Series of Courses


iOS and Android Boot Camps


Looking to jumpstart your iOS or Android development projects? The fastest way to be productive is to join us in the upcoming iOS and Android Boot Camps. In these boot camps, you will learn the fundamentals in 5 days, and at the end of the 5 days, you will be productive and on your way to coding your first real-life app.


AND500 - Android Programming Bootcamp
Course Fee
S$3197 (nett; no GST)
If your company is sponsoring you for the training, your company can enjoy 400% tax deductions/ allowances and/or 60% cash payout for investment in innovation and productivity improvements under the Productivity and Innovation Credit (PIC) scheme. For more details, check out the Productivity and Innovation Credit page. 
Schedules
Start DateEnd DateDetailsCategory
Mon Oct 24 2016Fri Oct 28 2016PDF

IOS500 - iPhone Programming Boot Camp
Course Fee
S$3197 (nett; no GST)
If your company is sponsoring you for the training, your company can enjoy 400% tax deductions/ allowances and/or 60% cash payout for investment in innovation and productivity improvements under the Productivity and Innovation Credit (PIC) scheme. For more details, check out the Productivity and Innovation Credit page. 
Schedules
Start DateEnd DateDetailsCategory
Mon Jul 18 2016Fri Jul 22 2016PDF
Mon Aug 29 2016Fri Sep 02 2016PDF

Monday, May 02, 2016

iOS Boot Camp

If your company is planning to go into iOS development, the 5-Day iOS Boot Camp is the most cost-effective way to get your developers jumpstarted. Available in Swift or Objective-C, this course focuses on all the important aspects of iOS development to jumpstart your developers in the shortest time.  We can conduct this course in house, or you can send your developers to our open classes.

Topics include:

  • Introduction to Objective-C or Swift
  • Storyboard
  • Location-Based Services
  • Design Patterns
  • Protocols and Delegates
  • Databases
  • Web Services
  • Background Fetch
  • Network Connectivity

We have conducted this course successfully worldwide. Contact Wei-Meng Lee @ weimenglee@learn2develop.net for details such as costing, venue, as well as in-house arrangements.

Learn iOS Programming using Swift

Learn how to program your iOS devices using Swift. In this course, you will learn the the fundamental building blocks of iOS programming:

  • Crash course in Swift
  • Using Storyboard
  • Views and View Controllers
  • Different types of applications
  • Location Based Services
  • Displaying Maps
  • File Storage
  • Background Fetch
  • SQLite Database

In addition, participants will also get 2 Swift cheat sheets updated to the latest version of Swift. These 2 cheat sheets are handy companions for every Swift developers! You can also download your own copy here:


 

Friday, April 15, 2016

Changes in Swift 2.2 - Selectors

Prior to Swift 2.2, you can use a string literal for Objective-C selectors. For example, in the following code snippet you could specify onTimer as the selector:

    func onTimer() {
        ...
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        delta = CGPointMake(12.0,4.0)
        NSTimer.scheduledTimerWithTimeInterval(0.05,
                                               target:self,
                                               selector:"onTimer",
                                               userInfo:nil,
                                               repeats:true)

    }

Because there is no checking to ensure that the selector name is a well-formed selector (or that it even refers to a valid method), this method of naming a selector is dangerous and hence deprecated in Swift 2.2. 

Instead, you should now use the new #selector expression that allows you to build a selector from a reference to a method. The above code now looks like this:

    override func viewDidLoad() {
        super.viewDidLoad()

        NSTimer.scheduledTimerWithTimeInterval(0.05,
                                               target:self,
                                               selector:#selector(ViewController.onTimer),
                                               userInfo:nil,
                                               repeats:true)
    }

If the target method accepts arguments, then the selector looks like this:

    func doSomething(num1:Int, num2:Int) {
        ...
    }

    override func viewDidLoad() {
        super.viewDidLoad()        
        
        NSTimer.scheduledTimerWithTimeInterval(0.05,
                                               target:self,
                                               selector:#selector(
                                               ViewController.doSomething(_:num2:)),
                                               userInfo:nil,
                                               repeats:true)
    }

While the old method of using string literal for selector is still supported in Swift 2.2, you should use the new syntax when updating your code.