An Introduction to Swift: Part 1

At WWDC 2014, Apple has introduced one of the biggest updates to iOS since 2008 from a developer's point of view. They introduced HomeKit, HealthKit, CloudKit, and Extensions, just to name a few. But the biggest surprise out of WWDC 2014 was the introduction of a brand new programming language, Swift.

Swift is a wonderful programming language that has been built from the ground up to be efficient and safe. It uses the same APIs that Objective-C does. Or, what you can do in Objective-C, you can do in Swift. It also introduces some new concepts longtime programmers will appreciate and some of which I will cover in this introductory series on Swift.

In this series, I'm going to assume you're already familiar with Objective-C. In the first article of this series, I talk about Swift's philosophy, file structure, and syntax. In the second article, I zoom in on more advanced aspects of Swift's syntax, such as optionals and memory management. Hang on to your hats, folks, it's going to be a doozy.

1. Philosophy

To better understand Swift, Apple has been conditioning us with structural improvements in Objective-C over the last few years. Objective-C improvements like code blocks, literal array and dictionary definitions, and ARC (Automatic Reference Counting) are but a few things Apple added to Objective-C that ease the transition to Swift.

One important pillar of Swift's philosophy is code initialization. All objects and variables  when defined in Swift must be initialized in code. An uninitialized object or variable will result in a compile time error in Swift. This ensures an object or variable always has a value. There's one special case in Swift for when an initial value cannot be defined. In this special case, your variable is called an optional. We will cover optionals in the second part of this series.

Another important pillar is branch completeness. All conditional branches, be it if or switch/case, must cover all conditions. This way, no code can fall through without it being covered. Missing a condition in your branch statement will be caught and generate a compile time error.

One last element of Swift's philosophy is its preference to constants over variables. Swift defines variables and constants in the following manner:

In the above example, the let keyword is used to define a constant while the var keyword defines a variable. By making the definition of constants this easy, Apple encourages the use of constants whenever possible. This leads to safer code in a multithreaded environment and better code optimization as the compiler knows a constant's value won't change.

Now, there's much more to Swift than a few syntax and formatting enhancements. Swift was built from the ground up to fix many common C/C++, and inherently Objective-C, sources of crashes. Issues like:

  • out-of-bound indexes in arrays
  • uninitialized data
  • unchecked return types
  • unchecked pointer access
  • implicit fall through 
  • goto errors

As someone who programs for both iOS and Android, I know first-hand how much more fun coding for the iOS platform really is with Cocoa and UIKit. This series will show you how much more fun coding can be by adding Swift to the mix.

2. File Structure

In Objective-C, we have header files (.h) and implementation files (.m). This is something Objective-C inherited from the C language.

In Swift, a class is defined in a single implementation file (.swift) that includes all the definitions and implementations of the class. This is reminiscent of other languages like Java and C#.

Gone is the need for juggling header files and adding the pesky #IFNDEF at the top of header files.

3. Syntax

The first thing you'll notice about Swift is the disappearance of the semicolon at the end of each statement. In Swift, each line is considered a statement and we don't have to add a semicolon at the end of each line.

I emphasize have to, because nothing stops you from adding semicolons at the end of your statements. I will continue to add semicolons at the end of each statement as I think it increases readability. Also, it's really difficult to get rid of the habit of adding semicolons like Cocoa developers have done for years.

Another important change in Swift is that curly braces are mandatory for if statements. That means no more Heartbleed bugs.

Syntax can be a complex subject to write about. Swift has a lot of subtleties that can take very long to go over, but that isn't the goal of this article. For brevity, I will concentrate on what changes an Objective-C developer would notice.

4. Similarities with Objective-C

I'll start off by showing you three code snippets that illustrate some of the similarities with Objective-C. It will help you in your understanding of the Swift language.

Objective-C programmers will find that Swift has the same branch and iteration statements you're already familiar with, such as if/else,  for loops, for..in loops, and switch statements.

Swift includes two range operators, ..< and ..., to specify a range of values. In the above for loop, we use the half-closed range operator, ..<, to specify a range of values that includes 1, 2, 3, and 4, but it excludes 5. The other range operator is the closed range operator, .... It specifies a range of values that includes the value on both sides of the closed range operator. For example, 1...5. specifies a range of values from 1 through 5, including 5.

5. Defining Variables and Constants

Let's revisit the example I showed you earlier.

In Swift, we define constants using the let keyword and variables using the var keyword. The colon, : ,is a marker to define types. In the above example, we're creating a constant and a variable of type String.

We're also initializing the constant and the variable with a string. In Swift, strings are defined just like C strings in Objective-C, they're not preceded by an @ symbol.

Objective-C is a strongly typed language, which means that the type of a variable or parameter must always be specified. Swift is also a strongly typed language, but Swift is a bit smarter as the compiler will infer a variable's type. The compiler also makes sure that no incorrect casting of variables occurs without your expressed knowledge and intervention.

If we rewrite the above example letting type inference do its work, then the code snippet looks as follows:

This is much better and the code is much cleaner. The compiler is smart enough to understand that someInt is an Int and someFloat is a Double.

6. Strings

One way to get an idea of the strength of a language is by exploring how it handles string manipulation. Objective-C has a lot of functions and features that let us handle strings, better than most languages, but they tend to be verbose and confusing from time to time.

Let's start with an Objective-C example. To concatenate two strings in Objective-C, we do the following:

In Swift, to append a string to another string, we use the + operator. It's that simple.

Strings in Swift are Unicode, which means that we can write:

We can iterate the characters of a string using a for..in statement as shown in the following example. We can use a for..in loop to iterate Unicode strings too. It's really that cool.

One last thing I'd like to cover about strings before moving on is string interpolation. In Objective-C, if we want to output a string with variables, we invoke [NSString stringWithFormat:]. In Swift, variables can be embedded. Take a look at the following example.

To use string interpolation, you wrap the variable or function call in parentheses and put a backslash in front of it, \( expression).

7. Arrays & Dictionaries

Array & Dictionary

As an Objective-C programmer, you're already familiar with arrays and dictionaries. Swift also has collection classes and adds a few additional features to them.

How do you use collections in Swift? In Swift, they're called Array and Dictionary. Declaring an array in Swift is similar to declaring an array literal in Objective-C, using a set of square brackets, [ ], but without an @ symbol preceding them.

The same goes for dictionaries. However, instead of using curly braces, you use square brackets.

Mutability

If an Array object is equivalent to an NSArray object and a Dictionary object is equivalent to an NSDictionary object, then how do we create mutable arrays and dictionaries in Swift?

The answer is very simple, declare the object as a variable. In other words, in the previous example someArray is the equivalent of an NSArray instance and someOtherArray that of an NSMutableArray instance. This applies to dictionaries too. In the previous example, someDictionary is the equivalent of an NSDictionary instance and someOtherDictionary that of an NSMutableDictionary instance. That's neat, right?

While Objective-C arrays and dictionaries can only contain objects, in Swift, collections can contain objects as well as primitive data types, such as integers and floats. Another important difference with Objective-C is that collections in Swift are typed, explicitly or through type inference at compile time. By specifying the type of the objects in a collection, Swift adds extra safety to these collections.

Even though we can omit a variable's type when declaring it, it doesn't alter the fact that the compiler will assign types to the objects in a collection. Using type inference helps to keep the code legible and light.

We can redeclare the Array and Dictionary objects we declared earlier as follows:

The compiler will inspect the collections during their initialization and infer the correct type. In other words, it understands that someArray and someOtherArray are a collection of String objects and someDictionary and someOtherDictionary are dictionaries with keys of type String and values of type Int.

Collection Manipulation

Adding an object or another array to an array is very similar to string concatenation in that we also use the + operator.

Manipulating dictionaries is just as easy.

Typed Collections

Earlier, I mentioned that collections in Swift are typed, but what does that mean? If we define a collection that contains String objects, you can only add String objects to that collection. Failing to do so will result in an error.

Let's look at an example to clarify this. We define a collection of Car objects. The following code snippet shows the Car class definition and a mutable array cars, containing three Car instances.

Behind the scenes, the compiler will infer the type of the array. If we want to add a new Car instance to the collection, we can simply use the + operator as shown below.

However, adding an object of a different type will result in an error.

This has the added advantage of type safety for fetching objects from collections. It also eliminates the need for casting collection objects before using them.

In our example, a Car object has an accelerate method. Because a collection is typed, we can grab an item from the array and immediately invoke a method on the object, in one line of code. We don't need to worry about the element's type since the collection only contains Car objects.

To accomplish the same thing in Objective-C with the same level of safety, we'd need to write the following:

Finally, to iterate an array, we use a for..in loop:

To iterate a dictionary, we also use a for..in loop:

As you can see, typed collections are a powerful feature of the Swift language.

Conclusion

 We've already learned quite a bit about the Swift language and you should take the time to let it sink in. I recommend that you download Xcode 6 as soon as possible and start applying what you've learned in this article in Xcode's new Playground feature. Playgrounds let you play with Swift in real time.

That's it for this article. In the next instalment of this series, we take a look at tuples, functions, closures, classes and last but not least, optionals. You'll also learn how memory management works in Swift. Stay tuned.

Tags:

Comments

Related Articles