Migrating From Objective-C to Swift

Swift is becoming more and more popular today and has even become open-source! Personally I've been following its evolution since the very first version was released and already have two working projects in production. I'm very glad that iOS developers have such a great opportunity to use this modern and powerful language in their toolkit, but such a rush to new and not fully tested tools can sometimes lead to unforeseen bugs and time-consuming problems that no one has ever (or very rarely) faced. This might be one of the reasons people are scared of using new and fresh instruments.

Nevertheless there are different ways to try out new things. You can first play around with pet-projects or start adding new features to existing projects using new tools.  I strongly believe that Swift is the choice of the future, though Objective-C will probably stay with us for a very long time.

To convince more of you to try Swift and save time by learning from mistakes I've made, I would like to share my experience of switching to this language after using good old Objective-C and discuss the differences between them.

Notice: This post was written while mostly using Swift 2.1 with Xcode 7.2 and migrating to Swift 2.2 in the end (no critical changes actually) :)


Let's start with the following simple and general question: what should change during transition to a new tool?

First of all, when starting to use a new tool, we should consider the reason it was created, its main purpose and the philosophy behind it, especially when talking about programming languages. Swift was designed to be a safe, fast and convenient language, absorbing all the best practices of modern software development, offering a user-friendly interface and the possibility of rapid prototyping and development, making a bunch of routine work for us and letting us know promptly if we are doing something wrong.

After reading the Apple’s official documentation of Swift, which is a small but well-structured book, I took on the project, in which I began to use in practice this new (but very interesting to me) language.

I often see that many people learn language syntax without getting into details and without thinking about its purpose. You should avoid this, especially since nobody is hurrying you and you have plenty of time to better understand the language and its features. This will help you to get the maximum profit from the new technology.

Development Environment

I would like to discuss the development environment, from more global things going deeper into details.

Currently having Xcode 7.2, it became a real pleasure to work with Swift. It started to crash less often, in fact, this version has almost never crashed. However, SourceKit is likely to fail and stops highlighting code components when editing some complex structures in which the compiler has to automatically infer a bunch of typing.


Unfortunately, here we lack the opportunity to perform refactoring in Xcode, even the primitive one which is available for Objective-C. But you can always try AppCode for this purpose, though I’m not sure if it’s fully compatible with Swift.

Screen Shot 2016-03-31 at 00.02.54

Playground and REPL

Often we want to quickly look at how a certain piece of code would work, test an algorithm, or prototype something. Swift has a great environment for such sandbox playing called Playground. I think it's a really cool feature, as it is inconvenient to create an empty project whenever you need to check something. The great thing about it, is it gives you visual feedback of what you are working with. It can be show as images, colors, diagrams, etc. You can find more on this in Swift Literals blog post.


Checking code snippets in the test target of an existing project, just because everything’s set up, is also not the best approach. Of course, if you want to test a piece of code from your project, just write a test for it. But Apple has given us such a nice thing as a REPL. Sometimes it may even be more convenient than Playground, since it does not try to compile every change in the code. It does not pour a lot of bugs on you while editing code, can support multi-line mode and gives autocompletion via strive Tab key, which in some cases makes playing with code faster and more pleasant (but I have not dedicated enough time to it yet).


Back Compatibility

Transition to the new versions of Swift does not yet support backward compatibility. Therefore, Xcode offers to fix compatibility errors automatically, which will solve at least 50% of the transition process, at the same time making you notice what has changed. Everything else should be fixed manually.

Swift version migration
Click to enlarge image


Despite the fact that we already use Swift, we still sometimes may need to use Objective-C code in a Swift project, or we want to start slowly to integrate Swift into our good old Objective-C project. Bridging is there for this purpose. Apple released a separate documentation on this in the form of a book. It really works and keeps elegant method signatures, just as we like.

Objective_C _to_Swift

Again, it has its own advantages and disadvantages. Let me start with what I like. I like that when inheriting from Objective-C type we gain access to KVO  and KVC . Since Swift does not give us such an opportunity, we can enjoy this former luxury using this trick. But of course, we have to pay something for this generosity, and these are features unique to Swift. We will talk about those features later. And that's what I do not like. When we declare, for example, the protocol with @objc  attribute or inherit our class from NSObject, their public interface may not contain features that are only available in Swift, such as generics, enums, etc.

That is why I try to reduce the use of Objective-C types only to Views and ViewControllers and Realm or CoreData data models.

In terms of what Apple does with Objective-C for compatibility with Swift, it adds new improvements to the language that help to translate Objective-C into Swift more clearly. For example, it adds Nullability annotations, which help us understand what values can be assigned nil in Swift. Another great improvement in Objective-C is the introduction of lightweight Generics, through which we can better understand in Swift what type of objects must be used in collections or other “generic-like” classes from Objective-C. Otherwise we would see collections of AnyObject.

@property NSArray<NSDate *> * __nonnull dates; 
@property NSSet<NSString *> * __nonnull words;
@property NSDictionary<NSURL *, NSData *> * __nonnull cachedData;
@property NSString * __nullable searchQuery;

And here's how it is imported by Swift:

var dates: [NSDate]
var words: Set<String>
var cachedData: [NSURL: NSData]
var searchQuery: String?

There is another less known addition in Objective-C: KindOf attribute. Roughly speaking, it helps us to specify “kind of type” and can be used as a generic constraint. It helps to specify an object’s type in a more flexible way than with a concrete class, yet still be more explicit than just using a common id, which is displayed as AnyObject in Swift. The type will be displayed exactly like the type that we want to see there. Those improvements may slightly cripple Objective-C, but they will make the transition to Swift as seamless as possible and we can see how much clearer Apple frameworks written in Objective-C become in Swift in the newer SDKs thanks to these helpers. Though there is one thing to be mentioned, none of the above mentioned improvements cause compiling errors when used improperly. They generate only warnings, so keep that in mind.

More about Swift and Objective-C interoperability can be found in one of WWDC 2105 - session 401 videos.

Project Design

Since Swift is considered to be partly a scripting language and has a lot of such traits, the structure and design of the project may also change a little.

No Headers Imports

For example, the number of files in the project is reduced by approximately 50% due to the lack of headers. In addition to that, we do not need to care about the import of individual files anymore. All we need to import are Modules.

import Foundation
import ReactiveCocoa

Of course we could create Umbrella header to gather all headers in our library, but it's just a trick that still needs to be maintained manually.


Finally, the modules kind of perform the role of namespaces and we no longer need to invent strange prefixes of two or three letters to distinguish our own classes from classes of others. I wanted to add that it became more common to divide individual application components and put them in modules, but this trend is not unique to Swift. I guess I started to notice it more in Swift. Argo, the library for JSON parsing, is a good example of this. It was divided into three or four modules: Box, Curry, Runes and Argo. Box was dropped along with the second version of Swift, and Curry seems to be just a little library to generate curried functions. Quick, a library for BDD testing, is another good example. It is divided into two modules as well: Quick as a test suite, and Nimble as a set of handy matchings.

Multiple Items per File

Locating several items in a single file is another feature, as well as the trend in Swift projects. In Objective-C it was customary to put individual classes, structures, enums, etc., in separate files. In Swift it is considered to be the accepted practice to have multiple dependent items in the same file, though it is clear that it is better to put fully independent items in different files.

For example, I find it useful almost every time I create a new class/structure. By default, a file in my project includes Protocol, Implementation, Extensions and Factory. Yes, I almost always access items by protocols instead of concrete implementations. Such an approach makes it easy to refactor and follow good design practices, though it may seem slightly fanatical in the beginning. And no, I have not found a suitable framework for the DI yet, so I manually create a factory for each item, and it knows what and how to inject into the object. I tried Typhoon, but I found it painful to use with Swift, however it fulfils its function perfectly for Objective-C, if you’re not against plists of course.

This is how average file in my project looks like:

// Here we simply import Modules.
// Other classes like Account are available 
// Because they're implemented in the same module as this class.
// Class should have at least internal access modifier to be available within module.
// Usually, your main Project Target is already a Module, so no extra steps needed.

import Foundation // We need this one for NSError class
import ReactiveCocoa // We need this one for SignalProducer class

// MARK:- Protocol

// I use to communicate via Protocols, so first let's announce it here
protocol AccountModel {
    func refreshData() -> SignalProducer<Account, NSError>

// MARK:- Implementation

// Then default Implementation comes
class AccountModelImpl: AccountModel {
    private let apiRequestsManager: ApiRequestsManager
    private let applicationSetup: AppSetup
    init(apiRequestsManager: ApiRequestsManager, applicationSetup: AppSetup) {
        self.apiRequestsManager = apiRequestsManager
        self.applicationSetup = applicationSetup
    func refreshData() -> SignalProducer<Account, NSError> {
        return apiRequestsManager.getAccount()
            .on(next: { [weak self] account in
                self?.applicationSetup.someInterestingData = account.someInterestingData

// MARK:- Factory

// And Factory is at the bottom of the file.
// It can have static or instance method, 
// And it can have multiple methods for creating different Implementations if we need them.
// Also it injects dependencies and setups our object if needed.
struct AccountModelFactory {
    static func defaultAccountModel() -> AccountModel {
        return AccountModelImpl(
            apiRequestsManager: ApiRequestsManagerLocator.sharedManager,
            applicationSetup: AppSetup.sharedState

// As we can see, we placed our Item in a single file, though it consists of multiple components.
// Such approach works great for me and reduces files amount and noise in project structure.

Language Vector


Before turning to Swift’s specific language features, I would like to briefly discuss its direction and positioning. Although Swift is a multiparadigm language, Apple presents it as a Protocol-Oriented language, as it is a trend now. What does that mean? It means that instead of inheriting bulky hierarchies, working with types through protocols is much more flexible. The protocols are flexible, they are not cumbersome, and they can be expanded by specific implementations in Swift. The Swift development team did a great job on the language and type system. Why is it necessary? It is necessary, of course, for more efficient abstraction, simplifying dependencies of items from each other, etc.  And it really works!

Values over References

Swift uses the best modern approaches and methods. One of them is striving to immutability. Many of us understand that mutable states can bring evil to confused developers, and this is partly the reason why the latest trends prefer functional languages and are trying to take a lot of things from them, as Swift did. In addition to that, Apple teaches us to assign values via let keyword that makes them immutable, and switch to var only when they really must be changed. Similarly, we are also advised to use Value types instead of Reference types, turning them to Reference types only if necessary.

let pi = 3.14
pi = 4 // Error!
var swiftVersion = 2.1
swiftVersion = 2.2 // Correct :)

In Swift, classes and functions are Reference types. Primitives, structures, and enumerations are Value types. How do they differ? In short and roughly speaking, Value types are copied, and Reference types are passed by reference. That is, by changing one of the copies, you will not affect the remaining copies in any way. However, changing the subject by reference, you change the object itself, and all reference to this object will see these changes.

Values VS References


And, despite the fact that copying an object is a pretty cumbersome operation, Swift creators assure us that by following their advice we will not degrade performance in any way.

A lot of Swift types use copy-on-write optimization and we can also use it for our own types. Actually Mike Ash describes these processes in detail in a few of his posts here and here. Or you can also find some answers in the official Swift Standard Library Reference.


Maximum security is another feature of the language. That is why type Optional is embedded in the language. We can clearly indicate through Optional whether the value can support nil or not. This is a big step from the times of Objective-C, where nil generally behaved strangely and was often the cause of many obscure bugs that had to be debugged. Seriously, in Swift, I use the debugger five times less than I did in Objective-C. Strong typing and such clear error handling allows you to write working code faster, because the compiler will not validate your code, until you handle all the possible cases.

var x = 42
x = nil // Error!
var y: Int? = 42
y = nil // Correct :)

var y1 = Optional(42)
y1 = nil // Correct :)

Language Features

Discussing the main goals and areas of language, we want to mention tools using which this is achieved.

First Class Functions

Of course, first-class functions are some of language features, giving it a functional tone. Here, we treat functions the same way as we do with values, returning them from functions, assigning variables, etc. Also we can transfer them into other functions.

func addTwo(x: Int) -> Int {
    return x + 2


Partial Application

Partial application allows you to create new functions from existing ones and thus effectively create complex functional structures and write more elegant code. This is actually cool for lazy evaluations.

func add(x: Int) -> Int -> Int {
    return { y in x + y }

let addTwo = add(2)

// or just

You can also explicitly create new function or use object with method to achieve same result, but don't you agree this is such a nice and easy way to create new constructions on fly? ?

func add(x: Int, _ y: Int) -> Int {
    return x + y

func addTwo(x: Int) -> Int {
    return add(2, x)

struct AddTwo {
    func execute(x: Int) -> Int {
        return add(2, x)

The only drawback in current Swift syntax I see is that you have to explicitly create a function that can be partially applied, while currying syntax is already deprecated in Swift 2.2 and there's no way to split function with "normal" signature into multiple functions from the box. For this purpose you can use Curry utility until then though.


Generics is the feature I have always felt the lack of in Objective-C. Finally, you can create generic data types or functions that can work with concrete types we need by specifying types or type constraints, and leaving all type-checking to the compiler.
For example let's create dumb version of Stack.

struct Stack<Item> {
    private var items = [Item]()
    mutating func push(item: Item) {
    mutating func pop() -> Item? {
        if items.isEmpty {
            return nil
        return items.removeLast()

// Now you can create Stack of any type that is allowed by its generic constraint
var intStack = Stack<Int>()
var stringStack = Stack<String>()

Type Inference

Type inference in Swift allows you to write very lightweight code, clean a bunch of unnecessary syntax noise and make the compiler care about all checks and type clarifying.

For example we don't have to say that xs is of type [String], Swift compiler does all the work for us, so we can quicker express our ideas with more freedom yet still keeping all that type strictness. I think this is awesome.

let xs = [1, 5, 2, 4, 3]

The only thing is that sometimes problems can occur if you use very complex structures. As a result, we get the "Expression was too complex to be solved in reasonable time" error. I hope it will be fixed soon. As an example is usage of Argo - JSON parsing library. It happens because there's too much work that needs to be done to calculate correct types, so it can be solved by specifying types you are working with.

Type inference error


Enumerations allow us to create very powerful types, where we can choose only one case and thus preserve a lot of the behaviour of the structs. Optional is an enum, along with various types of validation, and even network routers can be perfectly represented with enums. Moya (Swift’s networking abstraction layer) is a great example of it. They also have a strict type and are perfectly used in pattern matching, which brings the language another step closer to the functional programming language.

As an example, we can easily create such powerful yet ridiculously simple types like Optional or Result, etc.

enum Optional<T> {
    case None
    case Some(T)
enum Result<Value, Error: ErrorType> {
    case Success(Value)
    case Failure(Error)


Due to the fact that you can create your own operators and overload them with different functions, we get a lot of bonuses in the form of chains, pipes, handy parsers and more elegant expressions. Many may argue that custom operators are great, so this is just my point of view. Of course you can make your code unreadable using too many unknown operators. Therefore, you need a sense of proportion and balance. Personally, I try to use only operators which are well-known from such languages like Haskell or F#. In general, the community eventually comes to some conclusion, creating a standard which I try to adhere to. It helps not to get lost in a raging whirlwind of freedom and initiative. Such popular libraries like Runes or Operadics, which is used in Swiftz, have a bunch of operators that may simplify your code and using which you shouldn’t be scared of. There's even Swift Experimental API with even more operators, but personally I try to avoid such symbols as they are hard to find quickly on your keyboard.

We can easily create our own piping operator for function accepting single argument.

// Implementation

infix operator |> { associativity left precedence 130 }

public func |> <T, U>(x: T, f: T -> U) -> U {
    return f(x)

// Usage

let transformedX = x
    |> addTwo 
    |> prodThree 
    |> increment 
    |> square 
    |> pow

So this F#-like style is read much clearer than it would be written like one below or split into multiple expressions.


Standard Library

Swift has its own Standard Library along with Foundation. It becomes richer with every Swift release. And what is cool, we can easily cast types from Foundation to Swift Standard Library and back. We can even sometimes not notice how easily we switch between them. This is a sign of a well done job.

Let's take a look at strings

// creating NSString with Swift String
let nsstring = NSString(string: "hello, world!")

// creating Swift String with NSString
let string = nsstring as String


Publishing in AppStore is not much different.

An option "Embedded Content Contains Swift Code" appears in Build Settings, which is necessary if your Objective-C project has no Swift code, but it makes use of Swift frameworks. In this case, Swift Standard Libraries will not be included automatically and the application will crash trying to access their components. That is why you must set this option to YES to include that standard frameworks.

Another feature of the Swift application, which can be a little bit of a turnoff, is the large size of an application bundle. When I saw that the size of the application was 63 MB, I was terrified. In fact, this happens when building a project using Swift xcodebuild CLI with an Enterprise account. When I published the application to AppStore using Xcode Organizer, I noticed that the sizes of Ad-Hoc and AppStore builds were roughly 10-13 MB (as they should be). So developers who are trying to publish their apps in the AppStore should not worry about size of the application bundle, though it still will be a bit bigger because of including Swift standard libraries (maybe 5 MB more).

Swift Evolution

I would like to briefly note the direction in which Swift is evolving.

Starting from December 3, Swift became open source and it's great! Such resources as swift.org as well as a set of repositories in Github have appeared. Now everyone can contribute to Swift and its Toolchain. Thanks to all the efforts of Apple and open source community, version 2.2 of Swift language has been just released and in Swift Evolution Github repository you can see and participate in the development of the future language 3.0 version.

In general, we are witnessing and participating in the current and future development of the language, because the whole community can make the language the way it wants the language to be.

Here are a few things that I personally don’t like and would like to change:

Firstly, I’d like to have access to at least some dynamic runtime of the language. Of course, we can still do it using Objective-C data types, but it cannot be done working with pure Swift types, except for obtaining some kind of read-only meta information. When attending AppleTV TechTalks we were shown how to debug Swift code with Objective-C methods to access private API special debug methods. That is why I hope the situation will improve.

Secondly, it would be great to embed Swift core in the iOS itself. Currently each application stores all necessary Swift frameworks and Swift Core separately. I think Apple will fix this in the near future and all versions of Swift will be stored in the system itself, rather than separately in each application.

In conclusion, I would like to say that you should definitely try Swift! Not only Apple works on it but the whole world does as well. This a great opportunity to participate in its evolution and have it the way you want it to be.

Go ahead try it, contribute to it, and happy coding!

Subscribe to updates
Share this article

Contact me About

By sending this form I confirm that I have read and accept Intellectsoft Privacy Policy

Something went wrong. Send form again, please.

Thank you for your message!

We will get in touch with you regarding your request within one business day.

Send again

What happens next?

  • Our sales manager reaches you out within a few days after analyzing your business requirements
  • Meanwhile, we sign an NDA to ensure the highest privacy level
  • Our pre-sale manager presents project estimates and approximate timeline