Last week I downloaded the latest Xcode (V 8.0 beta - 8S128D) and converted one of my projects to Swift 3. Hence in this week's blog entry I'd like to talk a little about the reasons why I migrated early and the code I had to adapt for the migration. If you are looking for a general overview about what's new in Swift then check out Swift.org. They have a dedicated and definitely more detailed site for this.
Why migrate early?
For me there were actually to points that drove me to give Swift 3 a try:
- to get a hands-on experience early on. A lot of things have changed in Swift 3:
new classes, new value types, new syntax and last but not least new requirements for iOS 10. Watching WWDC videos is a must for any serious iOS developer but it doesn't replace any practical coding experience. You can use either playgrounds for that or an actual project. Former allows you to play around with different frameworks and types / classes specifically whereas an existing project provides you with an actual tangible overview of all the things that have changed.
- to run my code against the latest tools in the Xcode tool chain, especially the latest version of the static analyzer and the new thread sanitizer which is only available with Swift 3.
Migrating to Swift 3
Migrating an existing project can be done in three simple steps:
- create feature branch for migration
- perform initial migration with Xcode 8 migration assistant (Xcode 8 - Edit - Convert - To Current Swift Syntax
- adapt code manually to resolve remaining issues
Step 1 and 2 actually kind of go without saying. Hence let me tell you a little bit about what I had to do in Step 3.
There are new data types in Swift like URL or Date (which by the way unlike NSDate conforms to the comparable protocol). Although the Xcode converter did most of the work converting classes to their corresponding value type, I had to assist it a little whenever category methods were involved.
Dealing with Range changed a lot. There are now four different Range types. We have now Range, CountableRange, ClosedRange and CountableClosedRange (see here for more Information). The countable ones can be used in enumerations and uses for the non-countable counterparts can be found in String. Along with that some renaming took place as well. So what used to be startIndex / endIndex is now lowerBound / upperBound. Then handling ranges in Strings is different now too. startIndex / endindex properties are still there in String (in contrast to Range), but working with String indices needs to be done now via String.index() methods.
CoreData supports generics now. So if you perform fetch requests you now have to specify the type along with it as well e.g. NSFetchRequest<NSManagedObject>. In Swift 3 a lot of frameworks have become more Swift-like. CoreData is no exception here and profits like GCD now from the improved consistency and readability.
Last but not least I ran into a few minor conversion issues with Key Value Observing (KVO). Mainly due to the introduction of NSKeyValueChangeKey, which basically is a dedicated wrapper for String to be used with KVO.
All in all, it didn't take me more than hour to migrate an existing app project to Swift 3. Give it a try if not just for the fun and exercise.
iOS 10 requirements
When adapting an app to iOS10 be aware of a few pitfalls:
- New privacy rules: Apple requires developers to specify a reason via a corresponding usage description key (e.g. NSPhotoLibraryUsageDescription) in the app's plist file whenever an app needs to access user data (e.g. Calendar, Photos, Camera, Contacts ...). Apple clearly stated in WWDC 2016 session 709 that an app is going to crash if a framework's usage description can't be found. So check out Apple's documentation here to prevent your app from experiencing a premature termination.
- Last but not least, Apple is enforcing the rules around Application Transport Security (ATS). ATS had been introduced with iOS9 to retire plain old HTTP connections and enforce HTTPS connections for increased security. So far with iOS9 it's still possible to disable ATS in the plist via NSAllowsArbitraryLoads. At the end of 2016 however, Apple rejects any new app that doesn't have ATS enabled (There are still a few exceptions when dealing with WKWebviews by the way).
As I mentioned before, migrating your app to Swift 3 and iOS 10 is not going to be a big issue. Provided of course, you have a good understanding of the app to be migrated and some ideas of what's going to change in Swift 3. Mind that Apple doesn't allow yet any Swift 3 or Swift 2.3 app into the App Store.
New tools or improved ones are in general a good idea and I am quite happy about the new thread sanitizer which helped me squash a few bugs that even the current IOS 9 app is now going to profit from.
Last but not least I need to say that the Xcode - Beta as of this writing is not really ready for a production environment. I experienced just too many crashes. So it rightfully deserves its Beta - label. The Xcode console got quite noisy too. There are now just too many debug messages for the console currently to be useful at all. I hope that Apple is going to address this very soon in one of the next versions.