Using SwiftLint to generate code quality report for Gitlab

Gitlab allows you to easily measure and report code quality of your merge requests to see your linting or other code issues right in every merge request you make in a nice and concise way.

I have been using SwiftLint for a very long time now in my iOS projects so I decided to integrate it to the Gitlab code quality flow.

This is quite easy because SwifLint can generate a Code Climate format that Gitlab understands. No need for any custom format conversion or data transformation.

To set it up in Gitlab you need to modify your .gitlab-ci.yml file. First include the code quality template

  - template: Code-Quality.gitlab-ci.yml

and then add a new job called code_quality, it needs to have this exact name to match the included template

  dependencies: []
  stage: linting
      - codequality_report.json
      codequality: codequality_report.json
    - swiftlint --reporter codeclimate > codequality_report.json 
    - iOS-arm

This works for a simple project. In my projects I usually use an iOS application project and a few smaller framework projects that the iOS application uses, so instead of swiftlint --reporter codeclimate > codequality_report.json I call a custom shell script

[Read More]
Swift  iOS 

Correctly playing audio in iOS applications

When you look for a way to play audio in your iOS application you usually find code like this

player = try AVAudioPlayer(contentsOf: url)

While this code works and will play the given audio file it does not deal with all the nuances of audio playback.

Imagine the user is playing a podcast or music, do you want the sound in your app to stop that playback? Or play over it?

The key to correct audio playback is understanding AVAudioSession categories. Let’s take it by example

Playing ambient sounds over existing audio

If you want to play an audio file in your application without affecting the existing music or podcast playback that might be going on you should use the .ambient category.

You use this category for example to play sound effects like the sound of a message being sent in a chat application where the sound is not that important and definitely not worth affecting other playback in iOS.

You set the category on the shared AVAudioSession instance

try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)

and make it active

try AVAudioSession.sharedInstance().setActive(true)

All the sounds you now play using AVAudioPlayer will be played as ambient sounds.

Stopping existing audio to play your sound

If the audio file you want to play in your application is important, for example playing a received voice message in a chat application, you can stop existing audio that is playing on iOS.

You can achieve this by setting the category to .playback

try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)

Remember, setting a category makes it persist for all the consecutive audio playback until you set it to a different value.

When you play a sound now using AVAudioPlayer it will stop the music or podcast the user might be listening to.

But what if you want the users music or podcast to continue after you play your sound?

[Read More]
Swift  iOS 

Automatically merging conflicts in Xcode project files

Dealing with code conflicts is somethings every developer is probably used to, but it is never a good experience, especially when dealing with file formats that are not exactly human readable, like Xcode project files.

The Xcode projects files (project.pbxproj) are a proper mess with every file appearing multiple times, being referenced by an id, etc .. definitely not something you would want to deal with manually. Luckily there is a better way.


Kintsugi is lightweight tool to automatically resolve Git conflicts that occur in Xcode project files. You install the Kintsugi gem with

gem install kintsugi

and then simply calling it a path to a project as a parameter.

For example if you have a merge conflicts in App/project.pbxproj you execute

kintsugi App/project.pbxproj

and Kintsugi will take care of the conflicts for you.

I have been using Kintsugi for a few weeks now and I have to say it works really well. There was only one time so far it failed to automatically merge a conflicts I had in an Xcode project file.

Git  Xcode  iOS 

Allowing parallel iOS UI tests runs in CI

If you have your CI machine set up to run multiple jobs in parallel you might have encountered a problem. You cannot run multiple iOS UI tests in the same simulator at the same time. They will fail.

The problem

Imagine this scenario. You have one CI machine that allows two or more jobs to run in parallel. You have a UI tests job set up. Two of your developers push changes to their branches at (almost) the same time. The CI machine then tries to run two UI tests at the same time in the same simulator and at least one of them fails and has to be retried.

You can of course solve this problem by not allowing parallel jobs on the CI machine, but that slows down the CI process. There is a better way.

The solution

You can create a brand new iOS simulator instance for every job, run the UI tests in this new simulator instance and then delete it when you are done. This way no matter how many iOS UI tests jobs you run in parallel they will all use a separate iOS simulator instance and not affect each other.

Creating a new iOS simulator instance

The first step is to choose a unique simulator name for each job. You can generate some random guid for example. In Gitlab CI I just use the ID of the Gitlab CI job that is stored in the ${CI_PIPELINE_ID} environment variable

First you need to create the new iOS simulator instance at the start of the CI job

xcrun simctl create ${CI_PIPELINE_ID} `xcrun simctl list runtimes | grep iOS | awk '{print $NF}'`

This command creates a new iOS simulator instance with the given name using the iPhone 11 device and the latest simulator runtime. Using the latest simulator runtime makes sure that when you update Xcode on the CI machine you do not have to do any changes to you CI scripts.

Using the new iOS simulator instance

Now that you have a new iOS simulator instance created you can use it to run your iOS UI tests. You can simply pass the name to the xcodebuild command if you use it directly or use it instead of the device type when using Fastlane

[Read More]
CI  Xcode  iOS 

Generating boilerplate Swift code with GYB

How many times how you copied and pasted some code in your current codebase because there was no good way to abstract it? Maybe because it was some repeating code required by a framework or mapping of some data transfer structures.

Writing such boilerplate code is an error-prone waste of time, especially when there is a much better way: generating that code.

There are a few tools to help you do that, one of the most flexible of them being GYB.

What is GYB?

GYB is a lightweight templating system that allows you to use Python to generate text files. Those text files can be Swift source code files or anything else you need.

GYB is used in the Swift standard library codebase so it works well for generating Swift source code and it is a proven technology that works.

You can download GYB to your project from the Swift repository on Github

chmod +x gyb

I put it directly to the project directory and include it in the source control for simpler build and CI/CD setup.

Creating GYB templates

GYB templates for generating Swift source file look like Swift source files with some Python snippets for code generation.

This is probably best shown on an actual example. Let’s say you have a list of permissions that the app needs to support. Those permissions are then a part of a protocol and of a few structs.

[Read More]
iOS  Xcode