I began working on an iOS app called Healthy Baby at the end of 2014. At the time Swift 1.0 was already released and Apple was iterating on it rapidly, adding features and also changing the syntax of the language with each release of the SDK. It looked like the perfect time to start a new Swift project.
Note that this post is not about the difference of Objective-c vs Swift, nor about the new features of the language, but a log of the obstacles I found after choosing the Swift path. Embedded in the article you’ll find some tips about working with Swift, and I’ve also compiled a list of Swift-related techniques at the end.
At the foot of the mountain
Before deciding to go the Swift route I made sure to check for the interoperability of Swift with Theorem’s and other developers 3rd parties libraries. The interoporability testing really went well; going back and forth with Swift and Objective-C works like a champ in most cases. The only difference I found were some performance penalties but I didn’t think too much of it at the time.
Trying to be cautious, I searched around the web to see what others experiences were working with Swift so far. Most of the discussions were oriented around type-safety, concise syntax, generics, functional elements and minor stability issues, but I didn’t find any major complaints. So be it: after ingesting the two books Apple released about the language, ‘File > New Swift Project’ was clicked.
The climbing started
There will be some good impedance when trying to work with Cocoa on your first app. Swift is a bigger and more complex language, it moves (and adds) lot of validations to compile time, and you will feel it. If you haven’t used Swift before and want to see what I’m referring to: try to write a piece of > 15 lines of code without the compiler complaining.
New concepts like optionals, unwrapping them and the ‘implicitly unwrapped optionals’ will make your head spin a lot of times, but after a week or two you should feel comfortable with the language and the interaction with Cocoa.
So far, the language required a good investing of time to learn it but it kind of feels good after you read a completed class with the new concise syntax.
The top of the mountain
Just when everything seemed to be normal as I was overcoming the common trials and tribulations of learning a new language, I started to sense a bigger problem: critical aspects of coding were sluggish or even causing hard crashes. In order of ascending priority they were:
Out of no where, while editing your Swift files, it’s pretty to common to see error messages saying “SourceKitService Terminated” and you’re suddenly editing your file without code highlighting and no kind of editor assistance at all, forcing you to restart Xcode. In Xcode 6.1.1 this is happening once or twice per hour. Deleting your derived data may also help.
It is not only the crashes that are a nausance but the editing experience is degraded as well. The IDE started to feel sluggish when the project reached around 3k SLOC in my case, which is not a big project at all.
Additional crashes came while I was debugging with LLDB, the worst of which was when when I was trying to access a key in a Dictionary and half of the time Xcode had a hard crash.
These crashes happened often enough that the iOS community has created a project to help you idenitfy and report crashes. Here is a list of test cases that makes Xcode crash, so report your crash if you encounter one.
Crashes on release build
This was a difficult issue to track and catch, but seems that the swift compiler optimizes too much when dealing with ARC. In my case it was releasing a block that had to be retained in a dictionary value. The solution was to turn off all compiler optimizations, making the build one level above a debug build.
If you suspect you are in the same situation try turning off compiler optimizations for testing purposes.
This is what I consider a showstopper right now: if you change a single line of code in a class or file (even if no other parts of the project have dependencies on your modified file), it triggers the whole recompilation of the project. There are no incremental builds and no dependencies analysis on Swift right now. However there is one saving grace: if you use frameworks you don’t trigger recompilation of the rest of the application or any other frameworks. This means you can use frameworks to reduce recompilation impact.
From other people I heard the compilation time doesn’t correlate linearly with the size of your project but is related quadraticly (think
O(n²).) As an example a 3k SLOC with 16 Swift files compiles in 20 seconds in a 2.3 ghz i5 with 16GB RAM and a SSD disk. Any medium size and well architected (without dependencies loops) Objective-C project requires < 1 sec to compile (and maybe link, too) when you’re modifying and iterating over a single file.
I decided to move back to Objective-C, at least for the moving parts of my projects, those areas that change often and requires lot of iteration until you get it right. iOS development always had an incredible fast development cycle (modify-compile-launch) and sacrificing that fast cycle would have a detrimintal impact on my projects.
Here’s some tips in order to keep the project manageable if you decide to use Swift in your project:
- Use frameworks to reduce recompilation impact. modifying a file in a framework does not trigger recompilation of the rest of the app or other frameworks, so it’s a good choice to split your app in frameworks.
- Write base classes in Objective-C. This allows you to inherit those classes from Objective-C as well as from Swift in case you decide to switch in the future.
- Write class APIs without Swift-only language features. You will want to leave the doors of interoperability open so avoid using Swift-only features in the APIs of your classes: generics, tuples, enums, etc. leave them for the internal of your classes only.
- Write the stable parts of your app in Swift and the moving ones in Objective-C. This could be a wise decision if you keep an eye on dependencies, this is our current situation in Healthy Baby and the project is easy to manage and develop on.
Looking back, I would have loved to have a new language that starts small, with maybe just some syntax sugar compared to Objective-C but retaining the Objective-C semantics. Something similar to Eero, just a frontend change of the compiler, but that keeps all the performance and solid foundation of the Objective-C runtime and tools. Even something Coffeescript-like with Apple support would have made me happy.
Is Swift a bad language? No. Swift is definitely a modern language with lot of potential.
Should you use Swift on your projects? Maybe. It has some scaling issues right now if you’re planning to build a non-trivial app and you might want to avoid betting your app on Swift, especially if your app is mission critcal to your business. Teaching yourself to code or writing an app for fun? That might be a good time to give Swift a try.
Let’s hope Apple pushes to fix these problems in the near future and we’ll be able to start using Swift more frequently in our projects.