Biggest Day-To-Day Changes from Obj-C to Swift Part 2

Alright, you've seen swift a little bit here and there... you've seen some cool block syntax, now let's try to bring the main parts together so we can start building objects, classes. Swift offers many new exciting features that Objective-C has not taken advantage of, and hopefully with a base understanding of how to use Swift, you can start to venture into the full utility Swift offers.

1. Func-tions

Declaration

If you're a long time developer, Swift may look familiar already. It's basic coding style is very similar to javascript, but maintains much of the C structure that makes it even more powerful.

For those who want a quick refesher, the basics of the the Obj-C function is:

  1. - + instance or class method,
  2. (void) return type,
  3. someFunction: name of the function, (NSString *someString), and
  4. lastly the parameters of the function.

Now Objective C is special in that you can have additional names and parameters. Let's take a look:

Objective-C:

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{ ... }

Without going too far into Objective-C description, let's talk about how Swift is different. Walking through out previous function declaration, the class method vs instance is a little different in Swift.

  1. An instance method is simply defined as func, whereas a class method is actually defined with class func. That's right, you can have a class method inside a class object (both instance and class methods will be shown below).

  2. The return type is pushed to then end of the function with -> String.

  3. The name of the function only differs to be the first part of the Obj-C's name or description. From the previous example, that means the name would be: tableView( ... ), where everything inside the parentheses become argument descriptors and types.

  4. The parameters keep their names, tableView and indexPath in this example, but indexPath gets an added descriptor didSelectRowAtIndexPath

The Result:

Swift:

func tableView( tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { ... }

Recall the '!'? That means that the tableView that is sent is forcible unwrapped for the method to use. Most times you will use non-optional variables, but you may find it helpful for declaration (specifically for delegate methods).

Now let's take another look. Below, there are two examples of declaring functions; one instance and one class.

Objective-C (SomeObject.m):

@implementation SomeObject {
    + (void)someClassMethodWithoutParameters() 
    { ...}
    - (NSString*)someInstanceMethodWithInteger:(NSInteger)integer andString:(NSString*)string 
    { ... }
}

and now in swift,

Swift

class SomeObject : NSObject {
    /*class method*/
    class func someClassMethodWithoutParameters() { ... }   
    /*instance method*/
    func someInstanceMethodWithInteger(integer: NSInteger, andString string:String) -> String { ... }

We have different methods types, class and instance. Within these, we have the return types that are following the name (in this case the class method has no return object. Then we maintain the same feel of Objective-C with continuing the descriptor names inside the parameters of the function. To see these methods in use, let's see how they are called using Swift:

Swift:

/*using a class method*/
SomeObject.someClassMethodWithoutParameters();
/*using an instance method*/
var objInstance = SomeObject();
let value = objInstance.someInstanceMethodWithInteger(5, andString:"Hello");

If you noticed in the instance variable, we have the name of the function and then an internal "descriptor" for multiple parameters. This is where Swift really looks different from languages like Javascript, as it tries to keep the same feel as Objective-C.

Function Types

The function type is Swift's way of using blocks to pass functions around to be used in different scopes. Just like any variable, declaring a function type can infer the parameters and return variables. Here's an example not using the inferred method:

Swift:

func multiplyIntegers(anInteger:Int, anotherInteger:Int) -> Int {
    return anInteger*anotherInteger
}
var multiplyFunctionType: (Int, Int) -> Int = multiplyIntegers;

This is very close to what Objective-C called blocks, but with the main change of being able to store our function as variables. Say we have a function that was defined in a super class. We can now take that function and pass it through our other functions.

Trailing Closures

Probably the most important aspect of function types is being able to have a method take a function type, similar to Objective-C's completion blocks. In Objective-C you used blocks to define procedures to be called in another function's procedure. In Swift this is not different, but you have more options. You can pass other functions as function types, or using trailing closures (much like would do with blocks):

Swift:

func doSomeActionAndCompleteWithBlock(closure:(Int) -> Int ) -> Int {
    return 5 + closure(10);
}
/* passing a function to the function */
func multipleTwiceAndPrint(anInt:Int) ->Int {
    return anInt*2
}
let multiplyFunc = multipleTwiceAndPrint;
/* returns 25 */
doSomeActionAndCompleteWithBlock(multiplyFunc);
/*adding a function with a trailing closure 
 returns 35
*/
doSomeActionAndCompleteWithBlock({ anInt in
    return anInt*3
})

Notice that the trailing closure has an extra feature. In this example we had anInt in just after the starting curly brace. This is because trailing closures still makes use of parameters, but they are defined at the start of the trailing closure. The formula from Apple's docs is:

Swift:

{ (parameters) -> return type in
    statements
}

Read More about block's in Writing Completion Blocks With Closures In Swift.

2. Tuples

One of programmer's favorite data types now exist within an iOS framework, Tuples! Tuples are containers for a small collection of different types. For example you can have a single variable (tuple) containing other data types such as integers, strings and even a custom objects:

Swift:

/* storing code and string for httpStatus */
let httpStatus = (404, "Not Found")
/* returning an an integer and object, 
   possibly index and object in an array
*/
let someObjectFound = (25, someObject())

Sending Tuples can be very helpful when you want to send grouped information back from your function. An HTTP status is often represented as an array, but now you can use a more lightweight data type. Tuples has it's places, such as defining quick references, and passing small amount of variables. Tuples are best used when you have literal types ("Hello", 0, 50.20). They are not a replacement for arrays that can store large amounts of data; think of tuples as best used a short array without any functional methods. Let's see an example of how you can use tuples and when to use arrays:

Swift:

/* tuple use */
func giveMeAceOfSpades() -> (rank: Int, suit: String) {
    return (1, "Spades");
}
/* mix of using arrays and tuples */
func giveMeADeckOfCards() -> Array<(rank:Int, suit:String)>{
    var deckArray = Array<(rank:Int, suit:String)>();
    let suits = ["Spades", "Hearts", "Diamonds", "Clubs"];
    for (var s=0; s < suits.count; s++) {
        for (var r = 1; r <= 13; r++ ) {
            deckArray += (rank: r, suit: suits[s]);
        }
    }
    return deckArray;
}
let aceSpades = giveMeAceOfSpades();
print(aceSpades.rank) /* gives the rank of 1 */
var deck :Array<(rank:Int, suit:String)> = giveMeADeckOfCards()
deck.removeLast()   /* remove the last tuple in array */

To Summarize, tuples are great quick data types that can store information quickly and retrieve it fast. Tuples do no have methods, and are best to share small groups of information. If your data needs to contain state, methods, or even private information you should use class objects.

And unlike an array, Tuples can contain different types, and for the reason are great for storing multiple types. This is because Tuples use generic types.

2. Generics

What if you wanted to use a class or a function across multiple types? Say there was a swap function for objects. You could create a swap for Integer type and swap for String type, but why not use a single method to swap? This is generics!

In generics, you put a placeholder in angle brackets to represent a type to be filled out later. In this example, we use a swap function to be able to swap any two elements in memory. The objects swap, but are replaced in each other's memory referenced so that you can ensure that you are accessing the swapped value.

Swift:

func swapper<T>(inout x: T, inout y: T) {
    let tmp = x
    x = y
    y = tmp
}

First, we recognize that T is the generic placeholder. When we call the method, we will want to replace that T with the type we want (String, Integer, Array, etc). Notice that we are using T also as the parameter types. We do this to ensure that all generic types in this function are the same. Next we see this odd inout descriptor in out parameter list. This is important because we want to modify the parameter that is given to the function. Here we use & before the passed variables to say we want to edit that reference in memory. To call the swap, here are a couple of examples:

Swift:

let arr = ["Hello", "World"]
swapper(&arr[0],&arr[1])
/* arr now has: ["World", "Hello"] */
let arr2 = ["Cheese", "Burger"]
swapper(&arr[0], &arr2[0])
/*arr now has: ["Cheese", "Hello"]
  arr2 now has: ["World", "Burger"] */

Now an interesting thing about declaring constants with let is that these constants cannot be modified from their original declaration. In this instance, we have two constants of array length 2. That is all that really matters, changing contents of these two constants is feasable because it doesn't affect the original constant. Constants does however not allow an increase or decrease in size of arrays.

Now you may not have realized you were using generics already, when we use an array or dictionary, we have to tell specifically what is being stored in there. Swift uses generics to define these types so that we can do Dictionary<String, data-preserve-html-node="true" String> or Array<Integer data-preserve-html-node="true">, without having to have custom array or dictionary types for each basic type.

Another example of using generics, is in a class. Say we wanted to create a small object that we call a stack. This stack can take any type, but even more we want 2 or more stacks of different types:

Swift:

struct Stack<T> {
    var elements = T[]()
    mutating func push(element: T) {
        elements.append(element)
    }
    mutating func pop() -> T {
        return elements.removeLast()
    }
}
var intStack = Stack<Int>()
intStack.push(50)
/* stack now contains 50 */ 
var stringStack = Stack<String>()
stringStack.push("Hello")
/* stack now contains "Hello" */

Using generics allows you to make more less repetitive, and gives the chance to build very powerful frameworks. All programmers should try to attain the most DRY code possible, and generics are your friend. Use it and use it well!

4. Classes

We gave a quick look at classes with declaring class methods above. Let's take a little more look into how Swift uses classes in the UIKit framework. Let's take a look at a controller class:

Swift

import UIKit
class ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet var textLabel : UILabel
    var dataArray:Array<AnyObject>?
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        return UITableViewCell()
    }
    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return 0
    }
    @IBAction func buttonPushed(sender : AnyObject) {
        /* do something */
    }
}

The first thing to note is that because there is no header, we are defining our class method on a global scope. Over time, Apple will announce access control methods (private, protected and public), but for this example let's just assume that all methods are global. Next we see that we create a controller class ViewController that is the subclass of UIViewController. We know this because it is the first element in the class's extensions. We are also extending this class to conform to the UITableViewDataSource protocol.

Next we see class properties. Here we have an @IBOutlet to a UILabel in the storyboard. You won't see too many @ in swift, but they are definitely around, you will also see them for @IBActions. Notice our dataArray variable is of type optional. This is very common, because your array likely won't have any data yet. We do this so we can load that data from CoreData or other data sources. We also use generics, to say that the array can contain any object, because at this point we are unsure what is going to be stored in that array.

Overriding a function is important in the UIKit framework, because it informs the compiler, that this function is part of this parent's class hierarchy. This is a fairly easy thing to miss when you switch over, and Xcode will happily remind you that override is necessary for functions that are defined up in the inheritance hierarchy.

The should be self explanatory, and is just the syntax difference between swift and Objective-C. For comparison, let's see what is different line for line:


Class definition:

Objective-C:

/* in ViewController.h */
@interface ViewController : UIViewController <UITableViewDataSource>
@end

Swift removes the necessity for a header file and puts everything in the implementation of the class. Now you just need one file for ViewController.swift

Swift:

class Viewcontroller : UIViewController, UITableViewDataSource


Next thing we need for any class are Property definitions / declarations. Let's take a look at some IBOutlets as they are also represented differently in Swift.

Objective-C:

@property (nonatomic, weak) IBOutlet UILabel * textLabel;
@property (nonatomic, strong) NSMutableArray * dataArray;

Note the simplicity of Swift's declarations, and how IBOutlet has been moved to the front of the variable declaration.

Swift:

@IBOutlet var textLabel : UILabel
var dataArray:Array<AnyObject>?


Next we establish the methods of the class. Here we showcase the required UITableViewDatasSource methods:

Objective-C:

- (void)viewDidLoad
{
    [super viewDidLoad];
}
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexpath {
    return [[UITableViewCell alloc] init]
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 0;
}
- (IBAction)buttonPushed(id)sender {
    /* do something */
}

Recall, that functions in Swift keep the same feel of Objective-C functions, in that the secondary parameter names or descriptors are still maintained inside the parameter block:

Swift:

override func viewDidLoad() {
    super.viewDidLoad()
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
    return UITableViewCell()
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {    
    return 0
}
@IBAction func buttonPushed(sender : AnyObject) {
    /* do something */
}

Next...

That's just the tip of the iceberg! In the coming months, there will be exciting new design flow as well as the new features that Swift brings will broaden our perspectives on how we design, develop and hopefully deploy apps in the future.

Until next time!