How You Can Migrate from Objective-C to Swift

Since Apple released their own Swift programming language in 2014, a lot of developers have taken the opportunity to test its features and see how it compares to Objective-C. The general conclusion seems to be that in certain cases Swift is preferable to Objective-C.

What are advantages of Swift?

  1. Swift allows you to write less code.

  2. Swift is strongly typed, which means fewer crashes caused by working with types incorrectly.

  3. Swift looks similar to other popular programming languages and resembles English.

  4. Swift is faster than its predecessor.

These features make Swift very tempting. Let’s consider what you need to do if you decide to switch from Objective-C to Swift, and determine if making the jump is the right choice for you.

It’s worth mentioning that Swift is fully compatible with Objective-C. Apple provides a mix and match feature to allow developers to use both languages within the same project. This means that you can add new Swift features to an already existing codebase. At the same time, even though Swift and Objective-C use the same APIs, there are some differences that you have to keep in mind when migrating from Objective-C to Swift.

Optional types

In Objective-C you can call methods on nil objects (more precisely, you can send a message to a nil object), and these methods return a zero value. To prevent undefined behavior in the event of an unexpected nil value, you should perform nil-checks when needed. Swift introduces the concept of optional values. The optional type is declared like a generic enum:

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible

Programmatically, it is a type that can stand for either a value of Wrapped type or a non-existing value. Swift provides the syntactic sugar for making types optional, so instead of needing to declare Optional<String> you can just write String? You have two options for getting the wrapped value from the optional container. The first is optional chaining – the if-let conditional statement receives the value only if it exists. If you are completely sure that the optional variable is non-nil, you can use forced unwrapping. This provides the stored value without conditions if it exists, but crashes when you’ve made a mistake and that optional instance is empty.

In addition to regular optionals, there are implicitly unwrapped optionals, declared like String! Let’s have a look at different ways you can declare optionality.  

class ExampleClass {
   var nonOptionalString: String
   var unwrappedOptionalString: String!
   var optionalString: String?

   init(string: String) {
       nonOptionalString = string

nonOptionalString can never be nil. This property should be filled during object initialization. Providing the forced unwrapped nil object will lead to a crash.

unwrappedOptionalStringcan be nil, but if you try to access nil object, your program will crash.

optionalStringcan be nil and should be treated as a regular optional variable.

When writing Objective-C code, you can mark variables with _Nullable and _Nonnull type annotations. The Objective-C equivalent of the previous Swift example above would look like:

@interface ExampleClass: NSObject
@property (nonatomic, strong) NSString * _Nonnull nonOptionalString;
@property (nonatomic, strong) NSString *unwrappedOptionalString;
@property (nonatomic, strong) NSString * _Nullable optionalString;

- (instancetype)initWithString:(nonnull NSString *string);

Error handling

When throwing and handling errors in Objective-C, the last parameter of the method is a reference to NSError variable. If this method execution causes unacceptable behavior, an NSError instance should be created and written to the variable passed. After invoking the method that can produce an error, you should check the error parameter to make sure it’s non-nil.

- (nonnull NSString *)exampleMethod:(nonnull NSString *)param error:(NSError **)error {
   if (!param.length) {
       *error = [NSError errorWithDomain:[NSBundle mainBundle].bundleIdentifier
       return nil;
   // do work

Objective-C also provides an exception mechanism with the traditional try-catch-finally syntax, but Apple strongly recommends using it for development purposes only.

Swift requires you to mark methods that generate errors with the throws keyword. If the last parameter accepted by the method is the pointer to a pointer to an NSError instance in the Objective-C interface, it will be translated from Objective-C to Swift as a throwing method, and the declaration of the method above will transform into:

func exampleMethod(param: String) throws -> String

Objective-C lets you omit error handling of the error-returning method, but in Swift you have to handle errors explicitly. The objects that are thrown should be descendants of the Swift ErrorType.


Objective-C provides C-style enumerations, which are limited to primitive types only. Even when you need to map integer enumeration values to the corresponding strings to display to a user or send to the back end, you have to create an array or a dictionary – or use switch statement. But Swift provides completely new enumerations with many more options. Enumerations in Swift can be used in the same way they are used in Objective-C:

enum ExampleEnum {
    case ExOne, ExTwo, ExThree

Swift enumerations can store associated values. Every enumeration case can contain a predefined set of fields.

enum AnotherExampleEnum {
   case ExOne(String, Int)
   case ExTwo(Int)

Swift enumerations can store raw values and be recursive.

Swift also has various powerful features that distinguish it from Objective-C. These features include generics, strict type system, type inference, tuples, and nested types. In short, migrating from Objective-C to Swift is not a trivial matter. Here are some tips to make the process easier.

Tips for migrating from Objective-C to Swift

First, you should create a .swift file with the same name as the corresponding header and implementation files. If you need to access Objective-C classes from the new Swift file, you have to add an import directive for them to the bridging header file. If you need to access the new Swift class from Objective-C code, you must inherit it from the Objective-C class; otherwise it won’t be reachable. Then you have to rewrite the code manually, adopting the best practices from Swift and making classes backward-compatible.

If you Google “Migrate from Objective-C to Swift,” you’ll find several links that suggest tools for automated translation of code. There are both free and paid solutions. However, even the paid solutions are extremely limited in their functionality.

To see how these tools fare we created a very basic game in Objective-C and then tried translating it to Swift using several automatic translators. The first one we tried is web-based, and allows you to upload a complete Xcode project (but only if the project is less than 10 MB). The results were really not ready for production – we found more than 70 errors even though our program only had 7 small classes. These errors included incorrect optionals, incorrect type inference, leaving last parameter as NSError instead of switching to Swift error handling with try-catch, incorrect switching from __weak typeof(self) weakSelf= self; to [weak self], etc. We also tested a paid desktop application that costs $15, but the result was even worse. The desktop app we tested wasn’t able to import the entire project, so we had to copy and paste everything file by file.

Most people in the industry agree that Swift is on its way to becoming the main language for iOS development, so it’s advisable to use it for new projects. 

Conveniently, the mix and match feature allows you to work with both Swift and Objective-C classes as a part of the same project, so you don’t have to spend time rewriting your entire existing codebase in Swift.

Read also:




4.0/ 5.0
Article rating
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Would you tell us how you feel about this article?

We use cookies to personalize our service and to improve your experience on the website and its subdomains. We also use this information for analytics.

More info