Viewing entries in
iOS development

Comment

Swift closures

What a great invention! With closures you can put the code where together where it belongs and there is no need to pepper your code with little helper functions.

Here are some things you can do with closures:

brush: swift
func loadData(completion : (result : Int, success : Bool) -> (Void)) {
  completion(3, true)
}

loadData() {
   result, success in

   if success {
     print("Success! The data was \(result)"
   }
   else {
   print("Failure!")
}

Comment

Swift overflow operators

Comment

Swift overflow operators

No arithmetic overflow by default! What do I mean by this? Well, in the majority of languages I worked with, when you add to integers and the result is above the maximum integer, the result overflows and wraps over and you end up with a number of the opposite sign.

Swift takes a different stance at this. In Swift, integer operations are always checked for overflow and if overflow takes place, bad things happen. Well, bad things are not really bad per se, since they help you to find bugs. Let's see some examples.

brush: swift
var a : Int = Int.max
a = a + 1

When we run the code above in a playground, the following error is triggered:

Playground execution aborted: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

So, there is some sort of runtime checking that the value does not overflow. How is this done by the compiler? The code when compiled to x86 gives something like this:

0x108b11912 <+98>:  incq   %rax
0x108b11915 <+101>: seto   %dl
0x108b11918 <+104>: movq   %rax, -0x38(%rbp)
0x108b1191c <+108>: movb   %dl, -0x39(%rbp)
0x108b1191f <+111>: jo     0x108b11942
....
0x108b11942 <+146>: ud2

As we can see, the compiler increments the register (incq), then checks the overflow bit (seto) and finally jumps if there was an overflow (jo). The destination is an undefined instruction (ud) that triggers the exception. This is obviously much more expensive than a simple addition. There is no free lunch!

If we try the same code in the compiler, we get a more interesting error:

error: arithmetic operation '-9223372036854775808 - 1' (on type 'Int') results in an overflow
var a : Int = Int.min - 1
              ~~~~~~~ ^ ~

As expected, the compiler performed constant propagation and detected the error. Apparently the playground has less checks than the compiler.

In most cases, the overhead to check for overflow will be minimal and compensated by the added safety. However, there will be some cases where performance is needed. Swift solves this by using special operators: the overflow operators. These are the standard +, - and * preceded with an ampersand: &+, &- and &*.

The code above with overflow operators looks like this:

brush: swift
var a : Int = Int.max
a = a &+ 1

And the generated assembly is:

0x10214f929 <+105>: incq   %rax
0x10214f92c <+108>: seto   %dl
...
0x10214f944 <+132>: movb   %dl, -0x39(%rbp)

For some reason, there is still some overflow detection even though it is not directly used in the code. Perhaps there is some status structure used to record that some computation overflowed? To be examined later...

Comment

Segues in iOS

Comment

Segues in iOS

One of the most used patterns in iOS programming are passing data from an initial view controller to a target view controller and the inverse pattern. Hence this post.

Forward segues

In the initial controller, you need to define the action before the segue is taken:

brush: swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "NameOfSegue" {
        if let destinationViewController = segue.destinationViewController as? DestinationViewController {
            destinationViewController.parameter = whatever
        }
    }
}

The segue indentifier is defined in Interface Builder. The code above passes whatever argument to the destinationViewController. The destination gets all the data already initialized before the viewDidLoad function.

You never call prepareForSegue directly. It’s a message from UIKit to let you know that a segue has just been triggered.

We can define what is passed as the sender when we perform the segue programatically:

brush: swift
@IBAction func tappedButton(sender: AnyObject) {
    performSegueWithIdentifier("NameOfSegue", sender: UIColor.blueColor())
}

Unwind segues

Unwind segues are used to pop view controllers from the stack. a function must be defined in the destination controller and marked as an IBAction.

brush: swift
@IBAction func detailViewClosed(segue:UIStoryboardSegue) {
  if let detailsViewController = segue.sourceViewController as? DetailViewController {
    self.name = detailsViewController.name
  }
}

Information can be prepared in the source controller with the prepareForSegue function, as in the forward segue case.

UIKit uses the function canPerformUnwindSegueAction to determine how low in the view stack it has to go:

brush: swift
override func canPerformUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject) -> Bool {
  if (self.respondsToSelector(action)) {
    return self.unwindHere;
  }
  return false;
}

Comment