Virtually every new Apple release leaks in some form. We knew about the Apple Watch months before launch, iOS 7’s designs were literally mocked up prior to release and it’s common for all iPhone hardware to be leaked from Foxconn’s conveyor belt every August. But there was one announcement that made jaws hit the floor at WWDC 2014: Swift. As a lucky attendee of the conference, I can safely say the air of dread, confusion, and excitement in the crowd was palpable. There were bemused looks everywhere. It’s been the elephant in the room for every iOS Developer since.
Since the announcement, Swift has been aggressively adopted. RedMonk, a company that measures language usage called the adoption rate ‘meteoric‘ . In Q3 2014, it was ranked 68th. In Q1 2015 it was 22nd. To put it in perspective, Objective-C is 10th. Swift is expected to break the Top 20 in their next revision.
We made the decision to move to Swift about two months ago for our native code, I’ve written about 50 lines of Objective-C since. It hasn’t all been smooth sailing. The decision itself was based on a few factors:
- In the long term, it’s a logical assumption that Swift will be the language for all iOS Development, so being comfortable in it sooner is an advantage when Apple brings out Swift-only features to Xcode.
- For me personally and in my work in Teamwork.com, it was a good time to move. I was to only work on smaller, greenfield projects which would only exist as their own pieces of work.
Everyone has a subtly different initial impression of using anything for the first time, based on their experience, background, and skills.
Here’s my background: I studied Applied Computing and Video Game Design in College, where I experimented with iOS Development throughout. For my Final Year Project I made an iPad game which was controlled remotely via Bluetooth on an iPhone. From there, I worked as iOS Developer for two years, at which point I moved to Teamwork.com. So I’m not the typical breed of Software Engineer in the wild – my first language is Objective-C. It’s what I’m most comfortable writing in and it’s the language about which I’ve the deepest under the hood knowledge. Also, having used Objective-C and Cocoa Touch for the last number of years and having never used Objective-C or Cocoa Touch anywhere but together – means they have a really tightly coupled relationship when writing software. They go hand-in-hand. Effectively, for me, Objective-C may as well have been the Cocoa Touch Programming Language.
Having never really worked with other languages in great depth, please excuse me if I’m super excited by a nuance of Swift that’s available in other modern languages with years.
I’m just going to skim over a few things I’ve noticed over the last few weeks.
The first week of development was a frustrating experience, but that’s natural when moving to a new language. Having armed myself by reading Apple’s The Swift Programming Language, I was aware of the fundamentals and paradigms, to a degree – but in practice rewiring one’s brain to Think Differently takes time. A great book by Maurice Kelly helped smooth the process and I’d recommend it for any medium to long term Objective-C developer moving to Swift.
In terms of versions, Swift is at 1.2 stable, 2.0 usable with Xcode Beta. Code that works in 1.2 will be broken in 2.0. The language is continually changing and evolving and thus it’s very hard to say with certainty what is the best way to write certain things. With that said, there seems to be a number of ways to write even the most basic of things.
These all do the same thing:
Similarly, if we have a function called ‘function’ which takes a closure as a parameter, we can call that in many ways.
After the inital function, these all print out that returned string:
These are just some simple examples of multiple ways of ultimately achieving the same thing, but throughout the language, we can see similar usage.
Whilst it’s not the end of the world, having different ways accomplishing tasks, it means a few things:
- Not easy to standardize code in a team environment.
- Reading other code (even from the Apple Guidelines) can seem alien.
- Debugging code can be tough at the start – if you’ve an error it can be hard to know which part of your code is incorrect and which is fine, but structured in a different way.
- If we’re used to code being written to one way, it can be hard to know what the other way is doing if we haven’t been exposed to it before.
A fundamental feature of Swift is the concept of optionals. In Swift, we’ve got regular types like String and Int, and these can be represented as optional or non-optional. Non-optional means they’ve got a value, they can never be nil or NULL or any of the ways in Objective-C represents the absence of a value. Optional means they can have a value, or they can be nil. If we want to get the value from an optional, we need to unwrap it to expose the true value. Consider an optional Int like a sealed box that may or may not contain an Int – we won’t know until we try and unwrap it. We can’t use that value until we unwrap it either. Originally, this was a weird concept, not aided by the strange syntax for accessing optional types – and we could also ‘force unwrap’ values, our way of telling the compiler – “Stop complaining, I got this”. I’ve formed the consensus forced unwrapping, is often bad practice as it basically negates the safety that optionals bring.
As a whole I really like optionals, they offer a simple and clean syntax to nil checking as well as forcing the programmer to write safer code.
Type inference is the automatic deduction of data type in an expression. Basically, we don’t need to declare type – the Compiler is smart enough to figure it out. This notion was alien to me. During the first week of development, I did not use Type Inference at all. From my Objective-C habits, I was under the impression that not declaring type was less simple to debug. It led to a lot of code like this:
Which is exactly how it would appear if you did it in Objective-C. Really, it doesn’t make much sense declaring type here. It’s obvious what the type is from the MyClass constructor, I’ve happily moved to using Type Inference everywhere. The Swift compiler picks links up the type automatically as we code, so even if type is not actually declared we can easily check it by Alt+Clicking on our variable.
In the second image, we can see that newClass is of type Minor, which is a subclass of Major. So we don’t need to have our type declared everywhere, it’s just a click away.
No header files in Swift. Nightmare when trying to see our available classes. *Note: This has been addressed in Swift 2.0 and Xcode 7 Beta which computed header files – we get the readability of header files via the Assistant editor without actually writing them! *
It’s simpler, cleaner and nicer
Over these past few weeks, as I’ve become less of a developer writing code like Objective-C and more of a Swift developer, the benefits of the language have become more clear.
The language itself feels clearer and much more succinct than Objective-C. The best example of this clarity which comes to mind are Closures, which are Swift’s version of Objective-C’s Blocks (they’re just anonymous functions). The confusion surrounding Block’s syntax can be summed up by this website being both so popular and necessary. They sometimes look backwards, sometimes forwards and are generally confusing, especially to beginners.
Declaring an Objective-C block:
Swift’s Closures are thankfully more standardised. A Swift Variant of the website does indeed exist, but as you can see there’s much more clarity in the syntax. The syntax is the same as a function that takes a parameter and returns a value. There’s no confusion as we’re using the pattern everywhere already, and it’s simple to remember.
Declaring a Swift Closure:
This can be said for the large parts of the language. We see syntax patterns everywhere. The benefit of this is when we’re learning how to accomplish something in Swift, we’re often not having to remember how to actually write it like was so often in Objective-C. Often, the way we think it should be written is just the way it’s written.
Some other quick examples:
Adhering to a Protocol in Objective-C, once again, has it’s own unique syntax for that exact operation.
In Swift, we just reuse the same pattern as used for the inheritance.
Type Casting (with Optional Binding) and Type Checking in Swift are also really simple and similar.
Again, there’s loads more of these examples of a much more condensed language. In terms of using the language itself, this simplicity really helps development and makes it much nicer to use than Objective-C. Looking back over Objective-C, the classes feels clunky and overly cluttered.
Generally, I’ve no major problems with the language itself. I’ve accomplished everything I needed to accomplish, albeit sometimes differently than I’m used to in Objective-C. The problems I’ve found are with the support structures and tools themselves.
The biggest annoyances in Swift are in Xcode’s handling of the language. Xcode’s autocomplete feature (a pillar of reliance for all iOS Developers) was totally broken until Swift 1.2 and Xcode 6.3.2. Even now, I still regularly get compiler errors after using autocomplete which spits out a mangled function. Whilst the compiler warnings have improved, there are still warnings that have labels that make absolutely no sense and only a Google search will figure out what it’s trying to tell me. That said, these are rare.
The refactor tool in Xcode just does not work for Swift yet.
A major pain point is that it’s simply not possible to build a static library containing Swift code. At Teamwork.com, our iOS App is built with Appcelerator. After spending a few weeks writing a project Swift, with the idea to bring this into the iOS App as a Native Module, we couldn’t. There’s no other reason here, except functionality hasn’t been added to Xcode yet (I’ve filed a radar and it’s been marked as a duplicate – so at least Apple are aware of it).
With all the fanfare of Swift 2.0 announced at WWDC 2015, I made the mistake of downloading Xcode 7 Beta, opening my project, converting to Swift 2.0 using the auto convert tool (which ported about 75% of the code automatically), and carried on working on the project. Still using the Beta, a week later, I completed the work and sent a build to TestFlight so we could test. I was greeted with an error – can’t upload builds to TestFlight from beta software. I opened the project in Xcode 6, but Xcode 6 can’t compile Swift 2.0 code. Begrudgingly, I ported the code back to Swift 1.2 and uploaded the build.
Playgrounds are a nice, simple way of testing out code. I’d consider them the clearest learning environment available and are a brilliant way for actually learning to code. I’d envisage and encourage them to be used in classrooms.
The problem with Playgrounds is that they are standalone, independant projects. So they can’t be used with existing codebases. I’d imagine a common use case would be to create a Playground which can see the project being worked on and test out code from there, but it can’t be done.
I’ve also hit some bugs in the language itself.
- Objective-C used a pattern of Selectors quite a bit. So we’ve a function called ‘myFunction’. A Selector is used to identify that function at compile time, like so:
We can pass Selectors around, but mostly we use them to interact with Cocoa Touch functions. Say we want to react to a Long Press on a certain UI Element? We’ll have to use a selector. Right now, it seems the Swift Compiler can’t link up the Selector to private functions.
I hope this has shed some light on any iOS Developer considering the jump to Swift. It’s mostly fine, but it’s certainly not a complete solution right now. You’ll hit some weirdness, but the tradeoff is a nicer, more modern language. Try and flesh out what you want to accomplish before you do it and see if it’s supported. I’m sure there are more caveats, like not building a static library with Swift code in it. It would have been great for me personally to have been aware of that first, so I could have avoided two weeks development.