22 Jul 2014 Swift from an Objective-C developer’s perspective
After the most recent WWDC, most iOS developers aren’t talking about cool new iOS 8 features or APIs. Instead, they’re talking about a whole new language: Swift. Yes, you heard right – a whole new programming language. How exciting it is!
Apple has been working on Swift secretly for a few years. It is a modern programming language that takes the strengths of other popular languages (for example, Python) and avoids the bad things about Objective-C (for example, poor manual memory-management and awful block syntax). As Apple declared, it’s Objective-C without the C. Not only this, Swift is also able to access the Apple Cocoa Touch framework and share the same LLVM compiler as Objective-C, so they can be seamlessly mixed in a same project.
Now you might be just like me, wondering why Apple would introduce a new language for iOS and Mac OS programming. Let’s walk through some most exciting parts of Swift to see if we can find a reason.
Types
Type inference probably is the No.1 reason why I prefer to use Swift over Objective-C. Actually I think it is the most handy feature of Swift. In Swift, most of the time we don’t need to write type annotations. The Swift compiler will work out appropriate types from the value of variables. Because of type inference, the size of our code has been reduced.
Swift is also a type-safe language. It performs type checks when it compiles our code to make sure there are no mismatched types. This is one of the huge differences between Objective-C and Swift. Objective-C provides a dynamic runtime, which means it decides which method implementation to call right before doing so. If a method hasn’t been implemented, you even get a chance to redirect the call to another object.
In Swift, since the compiler checks all the types, when you call a method, instead of doing dynamic invocation, the compiler will directly call the right implementation at the right places. Compared to Objective-C, Swift not only enables us to find errors more quickly, but also brings a runtime speed improvement.
Closures
Blocks are extremely useful in Objective-C. We use blocks to pass around self-contained functions in our code – for example, event callbacks. However, the syntax of blocks in Objective-C is just awful. Even an experienced developer still needs to use templates when writing blocks.
In Swift, we avoid this pain and use closures to pass functions. Closures are similar to blocks, but with a more clear, elegant and simplified coding style. Here’s an example of declaring a method that accepts a block, and then invoking that method:
1. Objective-C:
//Define a method that accept two integers and a block as // parameters - (void)doSomethingWithFirstValue:(int)firstvalue secondValue:(int)secondvalue block:(int (^)(int, int))block { int result = block(firstvalue, secondvalue); NSLog(@"%d", result); } ... //A block add two integers together and return the result [self doSomethingWithFirstValue:3 secondValue:7 block:^(int firstValue, int secondValue) { return firstValue + secondValue; }];
2. Swift:
//Define a function that accept two integers and a closure as // parameters func doSomethingWithClosure(firstValue:Int, secondValue:Int, closure:(Int,Int) -> Int) { let result = closure(firstValue, secondValue) println(result) } ... //A closure add two integers together and return the result doSomethingWithClosure(3, 7, {(firstValue:Int, secondValue:Int)->;Int in return firstValue + secondValue })
Thanks to type inference, we can simplify it further:
doSomethingWithClosure(3, 7, {(firstValue, secondValue) in return firstValue + secondValue })
And if a closure is passed as the last parameter, we can move the closure out of parentheses:
doSomethingWithClosure(3, 7) {(firstValue, secondValue) in return firstValue + secondValue }
Single-expression closures can remove the return
keyword:
doSomethingWithClosure(3, 7) {(firstValue, secondValue) in firstValue + secondValue }
Swift even provides shorthand argument names to inline closures:
doSomethingWithClosure(3, 7) { $0 + $1 }
Nice!
Compared to blocks, closures are easy to write and read, especially when we need to pass a really long function. Besides the syntax, closures are also more flexible. For example, a closure enable us to directly return multiple types. To achieve the same outcome with blocks, we’d have to put return values in a collection then return that collection.
Closures are more widely used thoughout Swift than you might realise. There are actually three different types of closure. Functions are just a special type of named closure.
Similar to blocks in Objective-C, closures are able to keep values from their context, either by holding strong references or simply copying values. Fortunately, most of the time, we don’t need to take care of the memory management of closures; Swift does this for us automatically.
Optionals
If you come from Objective-C, you must be familiar with nil. Basically you can set a pointer to nothing at any time. Instead of nil, Apple introduced the notion of ‘optionals’ in Swift, which handle the absence of a value. How do optionals work? An optional is kind of like a box. When we define a value as optional, what we actually do is we put the value inside the box. The stuff inside the box can either be the value itself or nil.
To define an optional type, we simply add a ‘?
‘ mark at the end of the original type:
//Here we define an optional type let aString: String? = "hello world"
Accordingly, when we try to use the stuff inside the box, we have to get it out of the box first. Here we add a ‘!
‘ mark at the end to force to unwrap the value.
//To force to unwrap let unwrappedString = "The stuff in the box is " + aString!
Actually, there is a bug in this simple example. The ! should only be used when we know we do have a value, otherwise it will produce a compile-time error. Therefore, we almost always have to do a check before we unwrap the box.
//Here we do optional binding. let aString: String? = "hello world" if let unwrappedString = aString { println("The stuff in the box is " + unwrappedString) } else { println("Nothing in the box") }
Here we did an optional binding to get the optional type. By doing this, we do not need to add ! at the end anymore. Swift will check if it is nil and assign the value respectively.
There are some huge differences between Objective-C and Swift when use nil. In Objective-C, we can point any object to nil at any time. However, in Swift, only optionals can be nil, which means that non-optional types can never be nil. This forces us to be think carefully about when we actually want to use nil. For example, if a function expects to return a string, then it must return a string and this string cannot be nil.
In Objective-C, only objects can be pointed to nil. But in Swift, we can set any value to optional. Because under the hood, optionals are just a simple enumeration which contains a none and a generic type. It all amounts to further proof that Swift is a type-safe language.
Generics
The last thing I would like to highlight about Swift is generics. Generics is a new powerful weapon that doesn’t exist in Objective-C. With generics, we could use a placeholder type first and define this specific type later. Since swift is a strongly typed language and really strict about types, generics provide some essential flexibility. For example, here is a function that accepts generic parameters:
//compare a and b, if a > b, return true, else return false func compare<T:Comparable> (a:T, b:T) ->; Bool { return a > b; }
By passing generics parameters, now we could compare any types of parameters, as long as the parameter implement swift comparable protocols. Actually, whether you realise it or not, when we write Swift, we use generics everywhere. Because generics has been deeply built into Swift standard library. For example, in Swift, arrays and dictionaries are generic collections. And as I mentioned before, optionals is an enum that contains a generic type inside it. Apple strongly encourages us to use generics to write more flexible, reusable functions. Apple also covered some advanced generic topics very well in WWDC 2014 session 404.
In conclusion
As a new programming language, Swift has a really clean and clear style. It combines the advantages of Objective-C with the features of modern scripting languages. In terms of speed, it’s also faster than Objective-C. For developers, Apple Xcode 6 also supports Swift “live coding”, which shows results immediately while typing, enabling programmers to debug and explore more easily.
Most importantly, Swift’s clean syntax and powerful debug tools will attract more people to learn iOS programming. Because of the improvement of app speed, customers also be able to use better high quality apps. I think that by introducing Swift, Apple intends to speed up the app development process, and attract both more customers & developers.
On the downside, since Objective-C has dominated iOS programming for so long, it has a huge number of support communities and third parties libraries. It will not be easily replaced completely by Swift. So in a long time, I think both of them will exist in the iOS development space. But personally, I already prefer to write code with Swift.
No Comments