Why Is Swift Faster Than Objective-C?

There are a lot of opinions about Swift. Some accuse it of performance issues. Others, like Apple, count performance, simplicity, and safety among Swift’s merits. This programming language has been on the stage for quite a while, and a lot of developers are already using the fifth version. Many say that Swift 5 is much better than previous versions, including Swift 3, and definitely better than Objective-C. 

We don’t take anybody’s words for granted, so we decided to check for ourselves whether Swift 5 is better than Objective-C and Swift 3 in terms of performance. If you’re thinking about which to choose for your app development, Swift or Objective-C, check out our test results below to help you make an informed decision in choosing a faster languages.

What did we compare?

Swift and Objective-C can both be used for iOS app development. The Swift and Objective-C compilers are both based on the LLVM compiler infrastructure, and there’s a single iOS SDK for them. That’s why there isn’t much difference between the ways these programming languages work with Cocoa frameworks.

We decided to measure the performance of Swift 3, Swift 5, and Objective-C by comparing their data structures. For that, we used the Objective-C Foundation framework and Swift’s native solutions.

We wrote several tests to estimate the performance of different types of data structures – Array/NSArray, Dictionary/NSDictionary, and Set/NSSet – by defining write, read, delete, and find operations for each. For that, we used XCode 8.3.3 with Swift 3 and Xcode 10.2.1 with Swift 5 and Objective-C.

How we estimated performance of the data structures

The most common way to measure performance is to identify how long a data structure takes to complete a given operation. To find that out, we considered the execution time of operations with data. But how can we measure that exactly? Here’s what we did:

  • We started by defining the test structure and placing operation requests in the structure with two time notches. We started with NSDate, since it’s a basic class for any time-based operations. There are a few ways to measure execution time with NSDate. One is by using the following construction:
NSDate *startDate = [NSDate new];
 /* put here the code to estimate */
NSDate *endDate = [NSDate new];
NSTimeInterval operationTime = [endDate timeIntervalSinceDate:startDate];
NSLog(@"Operation takes %f ms", operationTime * 1000);

Of course, we could have substituted [NSDate new] with CACurrentMediaTime() for more precise results and wrapped this construction into the method with a block argument in which we would have sent the operation request.

But there’s definitely a more straightforward way to measure the execution time!

  • This solution is described in detail in an old-but-gold article about benchmarking. The C function dispatch_benchmark from the libdispatch library does everything for you. Unfortunately, it doesn’t work with Swift, as we can’t use Swift to call a private C-language API.

We needed something to test both languages, and we found it.

  • The XCTest framework is a convenient, powerful, and universal tool for both Swift and Objective-C.

XCTest template for Objective-C performance tests:

- (void) testSomeStructureSomeOperationSpeed {
 /* data structure generation */ 
 [self measureBlock: ^{
 /* operation under data structure */
 }];
}

XCTest template for Swift performance tests:

func testTreeInsertSpeed() {
/* data structure generation */
 self.measureBlock() {
 /* operation under data structure */
 }
 }

As you can see, XCTest contains a useful function called measureBlock. According to the methodology behind it, you should launch the test 10 times and then calculate the average to reduce the probability of getting random results. This function also calculates a relative standard deviation for a series of test attempts. This method seemed the right choice, but as it turned out, it wasn’t. We’ll explain this a bit later. To achieve the best results using XCTest, we needed 100,000 iterations.

Testing environment

We ran tests using the iPhone 7 iOS 10.3 simulator, as we needed the same conditions for Swift 3, Swift 5, and Objective-C.

The results

Array_With__-O0___None__Optimization

The first results show us that it takes about the same time for Swift and Objective-C to perform Array-Add and Array-Delete operations. But Objective-C completes the Array-Update and Array-Read operations much slower than any version of Swift.

With these results, we understood that it would be better to use the Release configuration to measure the time for operations, as this way we could get the most accurate results.

The Optimization Level flag is located in the build settings of the target.

Build_Settings_of_the_target

We changed the mode to Release (using the -Os optimization flag) and conducted the test again.

Array_With__-Os__Optimization

 

Now that’s surprising! The time for performing an operation in Objective-C changed for the better, but the results remained the same for Swift. Why is Swift more affected by the mode change?

It’s truly difficult to say why the results for Objective-C changed and the results for Swift didn’t, as there could be many reasons: the processor was heavily loaded, more time was spent providing operating memory for each element as optimization was performed for a significant number of elements. It’s quite possible that Swift had some kind of an element counter that didn’t return to zero, resulting in optimization being turned off.

Here are the results we got after optimization was on:

Array

Set

Dictionary

  • We ran Add, Update, Find, and Delete operations in Objective-C, Swift 3, and Swift 5 on NSArray/Array, NSDictionary/Dictionary, and NSSet/Set.

  • Objective-C and Swift 5 performed these operations in about the same time, but Swift 5 did better when it came to element search operations.

  • You can see that Swift 5 is way faster than Swift 3.

  • Swift 3 is the slowest by every measure.

Why XCTest is NOT the best way to measure performance

Even though we got the results we expected, there were some questions we had no answers to. The two biggest issues were the algorithmic complexity of operations over data structures and insufficient accuracy of the results to make any conclusions about performance. This test involved several side operations, which could distort the results of the experiment. Since the operation was carried out 100,000 times over one data structure, you can understand that it’s not easy to define what exactly had a major impact on the performance.

After we talked to other developers in our company, we decided to take a completely different approach to measuring performance. You can find it in the Master branch of our repositories for Objective-C and Swift.

A more effective approach to measuring performance

Since XCTest doesn’t offer sufficient flexibility and accuracy for measuring execution time of nanosecond operations, our next experiment excluded this test completely.

The new approach to measuring performance entailed experimenting with a pre-initialized data structure filled with a fixed number of elements (initial states). We did only one operation over the data structure, then created a new structure with a new initial state and executed the operation again. We considered 500 states per data structure and calculated their performance over 10 iterations.

For example, at first, we recorded the current time of the operation with an Array’s 0 state. After we created a new empty Array, we executed the operation and measured the time again. Then we repeated the same operation with new Arrays 10 times and calculated the average value. We carried out this operation 10 times for the same reason we did the XCTest 10 times – to reduce the probability of an accidental result distortion. These 10 attempts gave us a resulting average that we used for building the graphs of functions.

As mentioned above, we carried out the same procedure for all 500 states of all data structures and displayed the results in the graphs of each function above, where X is the initial state of the Array and Y is the average execution time for the given Array.  

The results

You can find our tests in the Master branches of these repositories: Objective-C and Swift.

Array_Add

  • Adding the first element to a dynamic Array in Swift 3 and Swift 5 is four times faster than in Objective-C.

  • The operation is performed in constant time O(1) in Swift 3, Swift 5, and Objective-C. As more Call objects appear, the time increases (most likely due to dynamic changes in the size of the Array).

  • For filled Arrays, the operation in Objective-C is performed two times faster than in either version of Swift.

Array_Delete

  • There is a significant gap between the performance of Swift 3/Swift 5 and Objective-C when deleting one element from an Array: Swift 3 and Swift 5 take longer than Objective-C, and the deletion time increases as the number of objects grows. The reason is that deletion is performed in linear time O(n).

  • The Array-Delete operation in Objective-C is linear initially, with a transition toconstant time at the end of a given section. Whereas for Swift, the complexity of the operation is linear throughout the entire interval.

Array_Read

  • Both Swift versions are 4 to 6 times faster.

  • Both Swift versions are more stable than Objective-C.

Array_Contains

  • Swift 3 and Objective-C perform about the same, but Swift 5 outstrips them both.

Array_update

  • You can see that the complexity of each function is O(1), and each function is executed in constant time. But for Swift 3 and Swift 5, the time increases depending on the number of objects.

  • Swift 5 starts 3 to 4 times faster, but when it gets to 500 objects, it takes about the same time for all languages.

Dictionary_Add

  • We can notice that the graphs are pretty similar. Objective-C and Swift 5 require equal time for an operation, and Swift 3 is the most sluggish.

Dictionary_Constains

  • The situation is a bit different for Array-Search: Swift 5 outruns Swift 3 and Objective-C.

Dictionary_Delete

  • Objective-C is 3 to 4 times faster for this operation than any of the Swift versions.

  • Swift 3 and Swift 5 have a wavy structure. Definitely, it’s connected to the dynamic change in the size of the Array.

  • All graphs seek constant time.

Dictionary_Read

  • All three languages show nearly identical time.

Dictionary_Update

  • Both Swift 3 and Swift 5 start two times faster than Objective-C.

  • More objects significantly increases the time for Swift 3 but only increases it a bit for Swift 5.

  • The execution time of an operation is constant O(1).

Set_Add

  • When considering long intervals with 500 elements, it becomes clear that the graphs for Swift 5 and Objective-C almost coincide.

  • Swift 3 is the slowest once again.

Set_Delete

  • Objective-C is 2 to 3 times faster.

  • All graphs demonstrate constant complexity, but the graphs for both versions of Swift are much more prone to random fluctuations.

What conclusions can we make?

  1. The Insert and Update operations in Array are similar for the three languages, but Read and Update in Array happen much faster in Swift 5.

  2. To increase performance, you should pre-initialize Dictionary and Set, with the maximum number of elements known in advance.

  3. All operations demonstrate great time results.

  4. Swift 5 is much better at doing the Contains operation compared to Swift 3 and Objective-C.

  5. Swift 5, Swift 3, and Objective-C perform the insert operations in Dictionary and Set equally fast, but Objective-C wins in all other operations.

  6. Arrays in Swift are preferred over other data types for all operations, except for Search if you have a large number of elements. In this case, Set is the optimal solution. Dictionary is absolutely ineffective. You should only use it if there is no alternative.

  7. The graphs of functions look pretty weird for a pure C-Array as it’s not a C Array at all. Objective-C uses complex inner data structures that aren’t arrays by nature but perform the array functionality. You can read more about them here.

Which language is better?

We compared the performance of Swift 3, Swift 5, and Objective-C, but we haven’t yet compared the coding solutions you get with them. There are a number of criteria we use to define the quality of languages. Do they have simple and clear syntax, a smart and helpful compiler, and safety that results in fewer bugs?

We compared these languages by writing the following data structures: LinkedList, Stack, Queue, and Binary Search Tree. We’ve also written a number of iOS apps in Swift 5, which has helped us get a feel for the new language. Based on all of this information, here is what we can say about Swift 5.

Swift vs Objective-C: Merits and shortcomings 

Here are the results of the performance comparison.

Benefits:

  1. Swift has a lot of cool things like safe memory management, strong typing, generics and optionals, and simple but strict inheritance rules. Oh, and the protocols! Swift has wide protocol functionality, and you can create code using the POP (Protocol-Oriented Programming) approach.

  2. Swift is cleaner and more readable than Objective-C. There are modules that eliminate class prefixes. It also has half as many files per project and an understandable closure syntax.

  3. Swift allows you to create flexible and lightweight classes that contain exactly what you want (no root class). I.e. if you want to print a description, just implement the CustomDebugDescription protocol, and if you want to compare, implement Comparable.

  4. Swift isn’t that fast, but it isn’t slower than Objective-C either.

Shortcomings:

  1. The LLVM compiler provides misleading and confusing errors (while typecasting and implementing generics, for example).

  2. Swift compiles code slower than Objective-C.

  3. Swift is relatively young and keeps changing. This has already resulted in a couple of painful transitions to newer Swift versions. Starting with the fifth version, however, Swift got ABI stability, which means the code shouldn’t change much in the future.

So which iOS programming language should you choose: Swift or Objective-C?​ Swift has made a big step forward since its initial release. The language is undoubtedly good for commercial use for projects of any size. You can hardly find a company that prefers Objective-C to Swift while creating Apple software today. The exception is enterprises that have to maintain legacy code. Still, developing apps in Objective-C takes more time than in Swift, as you’ll have to code more and the debugging will be more difficult due to strict typing. 

4.0/ 5.0
Article rating
138
Reviews
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?
Looking to develop an app?

Check out our services to find what you need

See our services

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