Few ways of improving your iOS APP performance in Swift (1)

Gordon Feng
Towards Dev
Published in
4 min readJul 22, 2022

--

If you have kids, you must wish your kids to grow up with good health and good physical.

Same as we build our APP, we all want our APP can crash free and more faster, So that comes this article, how do we improve our APP performance to make it faster is a lot of us’s long term goal.

So let’s get started to see what Apple suggests to us for how to Write High-Performance Swift Code, Part 1.

Enabling Optimizations

The first thing that Apple suggests to do is enabling optimization. Swift provides three different optimization levels:

  1. -Onone: This set is meant for normal development, it provides minimal optimizations and preserves all debug information.
  2. -O: This is meant for most production code, the compiler will perform aggressive optimization that can drastically change the type and amount of emitted code, but debug information will be emitted but lossy.
  3. -Osize: This specific optimization option lets the compiler prioritizes the code size over the performance.

for setting these optimizations options, can follow as following:

  1. ProjectNavigator.
  2. Select the project icon to enter the project editor.
  3. Select the icon under the Project header to enter the project setting editor.
Where you can modify the optimization level.

From here, you can specify the different ways to optimize for different targets by changing the Optimization Level field under the Build Settings.

Whole Module Optimization(WMO)

By default, Swift will compile the code separately during different files. This will allow Xcode to compile multiple files in parallel, making the Xcode compile much more faster.
But compiling each file individually will certainly prevent compiler optimizations. Swift can also compile the entire project as a single compilation unit.
Compiled with WMO mode, will most likely take a longer time to compile, but may run faster.

Where you can set the compile to WMO

Reducing Dynamic Dispatch

Swift is a very dynamic language like Objective-c, but different from Objective-c, Swift has given the developer ability to remove or reduce the dynamic dispatch to improve the runtime performance.

What is the Dynamic Dispatch?
Dynamic Dispatch is a dynamic way to call the method or property.
For example, Class is using dynamic dispatch by default for method and property access.
In Swift, there is a thing called vtable, this table is type-specific, which is referenced by the instances that contain the address of the type’s methods.

Dynamic Dispatch proceeds in two steps when the method is invoked:

  1. looking for the vtable from the object.
  2. looking for the method in the vtable.

The reason why reduce the dynamic dispatch:
So if there is a func/dynamic keyword declared in the vtable, Swift will emit calls via Objective-c message send. In this case, clearly it is way slower than calling the function directly. To improve the performance of this critical code, we often will want to restrict this dynamic behavior.

Restrict the dynamic dispatch by using Access Control
There are some access control that can restrict the dynamic dispatch:

1. final:
When the declaration does not need to be overridden.
This keyword can be applied to a class, a method, or a property, for marking that cannot be overridden. This implies that the compile can emit direct function calls instead of indirect calls.

C.array1 and D.array1 will be accessed directly. D.array2 will be called via a vtable.

2. private and fileprivate:
When the declaration does not need to be accessed from outside of the file.
This will allow the compiler able to ascertain all the other potential overridable declarations. Thus the compiler will infer the final keyword automatically and remove indirect calls for methods and field access accordingly.

e.doSomething() and f.myPrivateVar, will be able to be accessed directly, assuming E and F do not have any overriding declarations in the same file

3. internal:
If WMO is enabled, use internal when the declaration does not need to be accessed outside of the module.
Since the internal declaration is not visible from the outside of the current module, the optimizer can then infer final automatically to discover all potential overriding declarations.

let’s have a pause for now, we will resume in the next article. If this article helps, please give me some claps, Cheers:)

--

--