A Look at Apple’s Swift

| | 0 Comments| 11:03 PM
Categories:

In all honesty, when I first heard Apple had introduced a new language for developing iOS and OS X applications, I groaned. Does the world really need another language? More over, why go through the monumental task of introducing a new language for Apple development when Objective-C worked just fine? Of course, some may argue that Objective-C didn’t work just fine; that it was clunky, overly verbose, a dinosaur saddled with the trappings of C and all of the memory-management headaches that go with it. Or perhaps Objective-C had come to the end of the road in extensibility without making it look more like a mash-up of strange syntax (blocks, anyone?).

On the flip side, I am somewhat of a language whore. I enjoy learning new languages (computer languages that is, I’m still struggling to learn Spanish), and I particularly enjoy learning new ways of doing things in code. Coding in Ruby is a joy with its iteration constructs and blocks; thinking in Erlang is fun with its “everything is a function” paradigm. And I will admit to perhaps being one of the few people that appreciated Objective-C and its bracket syntax and named parameters in method calls. So naturally, I had to rush and download Xcode 6 Beta to play with Swift.

This post is about that experience and culminates in a look at using the FlatButton library (see our original post on using FlatButton) with Swift code. Apple got it right in that you don’t have to throw away your Objective-C code to use Swift. In fact, you can take an existing Objective-C project and start adding Swift files and using them with the rest of your code. We’ll show you how.

To get started with Swift though you are going to need the Xcode 6 Beta, and to use the Xcode 6 Beta you are going to have download and install OS X 10.10, also known as Yosemite. This tutorial is not about how to install Yosemite, or to necessarily provide tips on how to install it on a separate drive and boot into it and play around, though that is possible. It starts with assuming you’ve already done that and are ready to go.

Swift

Apple is known (for the most part) for only releasing new technologies when they are polished and ready, and Swift is no different. Immediately after announcing the language at WWDC, you could go to iBooks and download their The Swift Programming Language book. Other online development content already provides examples of using Swift with UIKit kit and the like. Of course, Swift won’t be fully available until iOS 8 is released later this year, but for a new language, it already has a wealth of documentation available.

The first few pages of the The Swift Programming Language book are pretty mundane, though, with simple examples like

[objc]
println("Hello, world")
[/objc]

and

[objc]
var myVariable = 42
[/objc]

How exciting! We learn three things right away with these examples, however, and that’s a) we are no longer encumbered with the NSString literal syntax of @"Hello, world", b) we didn’t have to define the variable type for myVariable, c) semicolons to terminate statements have been terminated. It feels just like a scripting language! Which, if you believe some of the online hype, is exactly what Apple intended.

The mundane gives way to the esoteric relatively quickly. Function definitions look like this:

[objc]
func square(x: Int) -> Int {
return x * x
}
[/objc]

Well, that’s clear as mud. Functions begin with the keyword func, followed by arguments to the function, and some strange -> syntax at the end, and then the braces and function body. In English, please. Even better, you could see a function definition like this:

[objc]
func multiply(thisNumber a: Int, byThisNumber b: Int) -> Int {
return a * b
}
[/objc]

Truth be told, I like the latter syntax because it keeps the flavor of Objective-C named parameters around. Known as argument labels, the additional terms thisNumber and byThisNumber, forces the programmer to use the labels when calling the function. I’m sorry, but verbosity is good, and you should love it. Consider the code:

[objc]
var circle = Circle(3)
var area = circle.area()
[/objc]

What’s the area of the circle? Who knows? It could be 28.26 if 3 is the radius, or it could be 7.07 if 3 was the diameter. How would you know without going looking up the implementation file or documentation? Here’s how!

[objc]
class Circle {

var radius: Double

init(radius r: Double) {
self.radius = r
}

func area() -> Double {
return M_PI * pow(self.radius,2)
}

}
[/objc]

A few things to note here, other than the obvious point of the argument label. Classes are defined with the class keyword, and properties are defined in the class body (after the opening brace). In this example we define a property called radius and declare it’s going to be a Double. Notice that we have to declare the type if we don’t give the variable an immediate value. That is, Swift can determine what the type is if we provide something like var radius = 0.0 (an implicit Double) or var radius: Double (an explicit Double). What it can’t do is read your mind.

Classes must have a class initializer (also known in the C++ world as a constructor), and while Swift can give you a free “synthesized initializer”, you are probably better off defining your initializers. In this case we used the argument label technique once more to show that we are initializing the Circle with its radius.

If we had left out the init routine (notice you don’t put func in front of init), the compiler would give us a complaint: “note: stored property ‘radius’ without initial value prevents synthesized initializers”. Fair enough, the purpose of initialization is to initialize the instance, and Swift doesn’t make an assumption like other languages that you want your variables to be defaulted to zero. You could get around this particular error by writing var radius = 0.0.

Now that our class is defined, we can use it:

[objc]
var myCircle = Circle(radius: 3)
var area = myCircle.area()
println("The area of my circle is \(area)")
[/objc]

Oh, my! More syntax changes. The constructor is now called with a variant of ClassName(), and out goes pointers and memory allocation and a bunch of brackets.

[objc]
Circle* myCircle = [[Circle alloc]initWithRadius:3];
[/objc]

Calling functions (methods) on the class instance use the “dot syntax” like variableName.methodName() rather than [myCircle area]. I once had a coworker on the business-side of the company ask me, “How are you able to type all of those punctuation characters without looking?!” I replied simply, “Practice. Lots of practice.”

And finally, take a look at the println there. Those that code in Ruby should read it as

[ruby]
puts "The area of my circle is #{area}"
[/ruby]

So, this has been fun thus far. Some new syntax and keywords, getting rid of the @ sign (we hardly knew ye), throwing out pointers and that often misunderstood [[alloc]init] pattern, but we get to keep some of the flair of Objective-C with argument labels. Of course this is the tip of the proverbial iceberg, and there are a lot more features of the language that are reminiscent of Objective-C (protocols, categories, etc.). We probably won’t get to those in this tutorial.

A Swift Xcode Project

For our first “real” Swift application, we will to redo our FlatButton tutorial in Swift. So fire up Xcode 6 and let’s create a new project called flatbuttonSwift or something like that. We’ll be doing again a Single View application. Note that when you create the new project you will get a Language option, and you can choose Swift.

swiftchooseoptions

You will notice your AppDelegate and ViewController files are now .swift files. Why Apple didn’t use a shorter filename extension, I don’t know. Probably because all the shorter ones have already been taken. For now, ignore both of those files and let’s add the Flatbutton files from the Github repository. You do this like you always do, select the files in the Finder and then drag and drop them into your Xcode project, making sure to select Copy items if needed. Here, you will get a new dialog box with some arcane message asking whether or not you want to “configure an Objective-C bridging header?” The answer is yes, you most definitely want to create an “Objective-C bridging header” because that is the magic that allows you to mix and mingle Swift and Objective-C files in the same project. So, don’t hesitate, click Yes!.

bridgingheader

When you do you will find that your FlatButton.h and FlatButton.m files are in the project, along with a file called flatButtonSwift-Bridging-Header.h. Now, notice this. Do you see any header files for your .swift files? That’s right, you don’t. Because Swift doesn’t have headers. Don’t ask me how they pulled that off or how it works under the hood, but Swift doesn’t have headers. So that .h file you see is an Objective-C header, and anything you put there is going to be exposed to Swift. Read that again. Any Objective-C header you import there is going to be exposed to your Swift files. So, naturally, we want to put

[objc]
#import "FlatButton.h"
[/objc]

in that file, because we want to expose our FlatButton class to our new Swift files.

Now, the easy-to-follow part is over, and it gets a little more, well, hard-to-follow. But once the lightbulb goes off, you’ll start using Swift even in your existing projects without worrying about how to utilize your Objective-C code.

Go to ViewController.swift, and we are going to add the viewWillAppear function (or I suppose we can call it method), like this. Stick it between viewDidLoad() and didReceiveMemoryWarning().

[objc]
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
}
[/objc]

More new keywords, in this case override. You can read more about it online, but its basically an explicit statement telling Swift, “I am overriding the base class method.” If you don’t put it the compiler says to put it there. Bossy compiler.

Now we have a spot to create our FlatButton. Here’s what the Objective-C code looked like for creating a decent Sign In button:

[objc]
UIButton* flatButton = [[FlatButton alloc] initWithFrame:CGRectMake(20,350,280,40)
withBackgroundColor:[UIColor colorWithRed:0.521569
green:0.768627
blue:0.254902 alpha:1]];
flatButton.layer.cornerRadius = 10;
[flatButton setTitle:@"Sign In" forState:UIControlStateNormal];
flatButton.titleLabel.font = [UIFont fontWithName:@"Avenir-Black" size:20.0f];

[flatButton addTarget:self action:@selector(flatButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:flatButton];
[/objc]

Okay, one thing at a time. We know that we are going to create a UIButton, but remember, we’re going to ditch the pointers and alloc, we’re going to add the var keyword in there, and there will be a lot less brackets. Let’s do it!

[objc]
var flatbutton = FlatButton(frame:CGRectMake(20, 350, 280, 40),
withBackgroundColor:UIColor(red: 0.521569, green:0.768627, blue:0.254902, alpha:1))
[/objc]

Add that code after the call to super.viewWillAppear(animated) and it should compile with no errors. So, what exactly is going on here?

First, the initWith phrasing of methods has ended. You no longer use the [[alloc] initWith] convention, the first argument to the method has been replaced with a named argument if it would have used the initWith pattern. Note, however, that the second argument, withBackgroundColor remains. Then, rather than using [UIColor colorWithRed:] naming, it is simply UIColor(red:,green:,blue:,alpha:). Rule of thumb: the first argument to your initializer will not have initWithThing, but rather, ClassName(thing:). Make sense?

The next statement is easy, it’s the same, just drop the semicolon:

[objc]
flatButton.layer.cornerRadius = 10
[/objc]

The next line

[objc]
[flatButton setTitle:@"Sign In" forState:UIControlStateNormal];
[/objc]

becomes a little something like this:

[objc]
flatButton.setTitle("Sign In", forState:UIControlState.Normal)
[/objc]

Looks similar, but not quite. Toss the brackets and @ (I never tire of saying that), but notice the enumeration UIControlStateNormal has been replaced by UIControlState.Normal. That is because enumerations are now named inside an enum structure and are “addressed” using the dot notation syntax. For example,

[objc]
enum Direction {
North,
East,
South,
West
}

var travelingDirection = Direction.East
[/objc]

Likewise, we no longer use UIControlStateNormal, but UIControlState.Normal.

Now, let’s set out font and size:

[objc]
flatButton.titleLabel.font = UIFont(name:"Avenir-Black", size: 20.0)
[/objc]

And finally, adding a target to the button.

[objc]
flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
[/objc]

Take note that the @selector syntax is gone and replaced with a simple String naming the method to call. There’s one area where we can all agree the verbosity got in the way. Of course, if we declared that there is a target method called flatButtonPressed: we better write one:

[objc]
func flatButtonPressed(sender: AnyObject) {
NSLog("flatButtonPressed")
}
[/objc]

And don’t forget that we need to add the UIButton to the view:

[objc]
self.view.addSubview(flatButton)
[/objc]

Putting it all together, here’s what our methods look like in ViewController.swift:

[objc]
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)

var flatButton = FlatButton(frame:CGRectMake(20, 350, 280, 40),
withBackgroundColor:UIColor(red: 0.521569, green: 0.768627, blue: 0.254902, alpha: 1))

flatButton.layer.cornerRadius = 10
flatButton.setTitle("Sign In", forState:UIControlState.Normal)
flatButton.titleLabel.font = UIFont(name:"Avenir-Black", size: 20.0)
flatButton.addTarget(self, action: "flatButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(flatButton)

}

func flatButtonPressed(sender: AnyObject) {
NSLog("flatButtonPressed")
}
[/objc]

Run this code in a simulator, or, if you upgraded your iPhone to iOS 8, you can run it there as well. You should see the green Sign In, and when you press it you will see the flatButtonPressed log in your console.

And that’s it really! Of course, this has not been an exhaustive review of Swift. There are arrays, dictionaries, protocols, extensions (known as categories in Objective-C), and the mysterious looking ? and ! characters in variable declarations. That’s probably worth a post on its own.

The complete source code for this post can be found on Github, just make sure and look at the swift branch!

Leave a Reply

Your email address will not be published. Required fields are marked *