Improve code quality

Spice up warnings and SwiftLint FTW.

It’s very important to take care of code quality at the very early stage of the development. Later it will just stack up and get back to you anyway. In this section I will just briefly introduce basic concepts of code quality, there’s more to come, which will be covered in tools section later.

Let’s start with something simple and forgotten: warnings.

Warnings are often ignored as they don’t stop you from compiling the code. But this is a mistake, you should treat them as errors.

To see how it works, create an obvious warning in AppDelegate:

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    // test warnings as error
    let i = 10

    return true
  }

After compiling you will see this warning:

Warning

Now let’s boost warnings in project settings. Go to iOSProjectStarter > Build Settings, search for Treat Warnings as Errors change it to Yes:

Warning

Now clean project (⇧⌘K) and try to compile, you should see an error:

Warning

Having warnings as errors during the development can be very painful, many times you will be unable to quickly write the code to refactor it later. It’s up to you, you can enable it only for Release or both.

SwiftLint

SwiftLint is a tool that helps you to follow Swift style and conventions. It integrates with Xcode, so you can get warnings and errors displayed inside the editor.

To install SwiftLint use Homebrew:

brew install swiftlint

To integrate SwiftLint into Xcode select target iOSProjectStarter > Build Phases > and add New Run Script Phase:

SwiftLint integrate into Xcode

Input this script:

if which swiftlint >/dev/null; then
    swiftlint lint
else
    echo "Warning: Install SwiftLint"
fi

This script will be executed with each build. Now try to build a project (⌘B):

SwiftLint warnings and errors

That’s a lot of warnings and errors. But don’t worry about them, almost all of them come from the installed dependencies. We need to add configuration file with all of the rules for SwiftLint.

Create a new file .swiftlint.yml inside project’s main directory:

disabled_rules: # rule identifiers to exclude from running
#  - colon
#  - comma
  - control_statement
#  - trailing_whitespace
opt_in_rules: # some rules are only opt-in
  - empty_count
  - missing_docs
  - cyclomatic_complexity
  # Find all the available rules by running:
  # swiftlint rules
whitelist_rules:
excluded: # paths to ignore during linting. Takes precedence over `included`.
  - Carthage
  - Pods
  - iOSProjectStarterSpec/
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
  severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 510
# they can set both implicitly with an array
type_body_length:
  - 300 # warning
  - 400 # error
# or they can set both explicitly
file_length:
  warning: 500
  error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
  min_length: 4 # only warning
  max_length: # warning and error
    warning: 40
    error: 50
  excluded: iPhone # excluded via string
function_parameter_count:
  warning: 3
  error: 6
cyclomatic_complexity:
  warning: 2
  error: 6
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle)

As you can see above, the directories Pods/ and iOSProjectStarterSpec/ are excluded from linting. Now let’s build it:

SwiftLint warnings

That’s better, just a couple of whitespace warnings. Those can be automatically fixed by autocorrect:

$ swiftlint autocorrect
Loading configuration from '.swiftlint.yml'
Correcting Swift files in current working directory
Correcting 'ViewController.swift' (1/2)
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/Modules/Main/Controller/ViewController.swift:24 Corrected Trailing Newline
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/Modules/Main/Controller/ViewController.swift:22 Corrected Vertical Whitespace
Correcting 'AppDelegate.swift' (2/2)
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/SupportingFiles/AppDelegate.swift:49 Corrected Trailing Newline
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/SupportingFiles/AppDelegate.swift:15 Corrected Vertical Whitespace
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/SupportingFiles/AppDelegate.swift:47 Corrected Vertical Whitespace
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/SupportingFiles/AppDelegate.swift:18 Corrected Trailing Whitespace
/Users/mike/Documents/projects/iOSProjectStarter/iOSProjectStarter/iOSProjectStarter/SupportingFiles/AppDelegate.swift:21 Corrected Trailing Whitespace
Done correcting 2 files!

I strongly encourage you to use SwiftLint, after a while you will realize that all of those rules are here to help. Your code will be more consistent and cleaner. Of course this is not a silver bullet, it will not save you from all bugs in your code or bad architecture decisions.

In the next step we will take a closer look at AppDelegate.