SwiftLint in Depth

Learn how to use and configure SwiftLint in detail, as well as how to create your own rules in SwiftLint for your project. By Ehab Amer.

5 (6) · 4 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

What Are SwiftLint Rules?

When you ran SwiftLint earlier, it reported several violations in the starter project. You didn’t configure or specify anything about what violations it should catch. So why did it catch those violations?

SwiftLint contains a huge set of rules it can detect. Not all teams have the same guidelines, so those rules are opt-in only. But SwiftLint has some rules at its disposal, which are what it applies in the project.

One rule producing many warnings is orphaned_doc_comment. You can find more about it in the documentation.

Also, the official documentation has the list of enabled rules by default and the ones you can enable yourself. You’ll see how you do that shortly.

Warnings and Errors

Notice that some violations are errors and others are warnings. SwiftLint gives you control over which rules are errors and which are just warnings. An error would fail the build whereas a warning would let the build pass, but alert you to the mistake.

Using Rules File

The default file SwiftLint looks for is .swiftlint.yml next to the project file. Because the file name starts with a dot, the easiest way to create it is through Terminal.

Go back to Terminal and ensure you’re on the path of the starter project. Then, type the following command:

touch .swiftlint.yml

This creates a hidden file named .swiftlint.yml. To view the file, go to the project folder in Finder. Press Shift-Command-, to show hidden files in Finder.

Starter project with the hidden file .swiftlint.yml

Structure of the Rules File

The file you created is where you configure everything about SwiftLint. You can disable some of the rules that are on by default and enable others. Or you can specify only a particular set of rules to enable. The first approach uses the default rules specified internally in SwiftLint. These default rules are subject to change according to the version of SwiftLint. The second approach completely ignores all the default rules and specifies only the ones you want. This approach would have the benefit of the set of rules not changing when SwiftLint is updated.

Neither option is better. It’s all about how you prefer to control it.

In the rules file, you can also specify files and folders to ignore. For example, you might have some third-party libraries in the project folder or some generated files you don’t want to cover in the checks.

Excluded List

The current project installs the Nuke library via SPM which downloads to the project directory. SwiftLint is reporting a significant number of violations in it.

Note: If you do not notice any violations from within Nuke then it’s because your DerivedData folder is not set to be in the project directory. Check out the Getting Started section of this tutorial and make sure you followed the instructions there.

Open .swiftlint.yml, which should be empty, and enter the following:

excluded:
  - DerivedData

Save the file, then build the project.

Notice that the number of violations dropped significantly! You now have only the SwiftLint violations from your project’s code.

Number of errors and warnings dropped after excluding the DerivedData folder

Disabling Rules

One rule is crucial for a project: orphaned_doc_comment. This rule reports a violation on every comment line.

Return to the rules file and add the following at the end:

disabled_rules:
  - orphaned_doc_comment

Updated rules file with excluded DerivedData folder and excluded rules

Save the file and build the project.

Now, that’s much more realistic to work with.

Configuring Rules

Your project still doesn’t build due to the three errors SwiftLint is reporting. If you’re introducing SwiftLint into a large project a team has been working on for years, you’ll have many more than three errors. It’s not realistic to completely fail the project at this point. It would be more convenient for you and the team to reduce the severity of those violations from errors to warnings to unblock the whole project. This is where rule configurations come in.

The two error-generating rules are force_cast and identifier_name. You can configure rules to match your needs.

At the end of the rules file, add the following:

force_cast: warning # 1

identifier_name: # 2
  excluded:
    - i
    - id
    - x
    - y
    - z

The configuration you added consists of two parts:

  1. force_cast has only one configuration possible, which is to set it to either warning or error.
  2. identifier_name allows for more configurations. The list of variable names allows them to exclude. The project uses i, but the others are also common variable names that break the rule but are acceptable to us.

Build the project, and now it will finally succeed. The two errors from force_cast are showing as warnings. As for the one from identifier_name, it has disappeared.

Disabling Rules Through Code

There’s another way to disable a rule. You can ignore a rule by adding a comment before the code block that produces the violation. For example:

// swiftlint:disable [rule_name], [another_rule_name], ....

This disables the specified rules completely. Starting from this comment until the end of the file or until you enable them again:

// swiftlint:enable [rule_name], [another_rule_name], ....

There’s also the option to disable a rule that’s appearing in the next line and the next line only:

// swiftlint:disable:next [rule_name], [another_rule_name], ....

But if the rule isn’t triggered in the next line, SwiftLint will warn that this disable is pointless. This can be handy so you don’t worry about re-enabling the rule again.

In the starter project, you’ll find a couple of SwiftLint disables. Those rules didn’t play well with Regex expressions and don’t apply there. This is why it’s important to understand the rules and know when they make sense and when they don’t.

Fixing the Violations

Almost every time, the message from SwiftLint describes why there was a violation.

For example, find the warning in the Issue navigator:

Comma Spacing Violation: There should be no space before and one after any comma. (comma)

Tap this warning. In ProductionsListView.swift, you’ll see there’s a space between MarvelProductionItem.sample() and the comma in the first two items. Remove these unnecessary spaces:

ProductionsListView(productionsList: [
  MarvelProductionItem.sample(),
  MarvelProductionItem.sample(),
  MarvelProductionItem.sample(),
  MarvelProductionItem.sample()
])

Build the project. Those warnings have disappeared!

Next is the warning for line_length. The line causing this warning in MarvelProductionItem.swift is:

posterURL: URL(string: "https://m.media-amazon.com/images/M/MV5BYTc5OWNhYjktMThlOS00ODUxLTgwNDQtZjdjYjkyM2IwZTZlXkEyXkFqcGdeQXVyNTA3MTU2MjE@._V1_Ratio0.6800_AL_.jpg"),

This is a lengthy line, but it can be confusing if you break a URL into many lines. For that, configure line_length to ignore URLs. Add the following rule configuration at the end of the rules file:

line_length:
  ignores_urls: true
  ignores_function_declarations: true
  ignores_comments: true

This ignores the line length rule for URLs, function declarations and comments.

Now open ProductionYearInfo.swift, and see the first case inside ProductionYearInfo is producing a warning:

case produced(year : Int)

The colon rule checks that there’s no unnecessary space before the colon and only one space after it. As you see in the line mentioned, there’s a space between the year and the colon. Removing this space resolves the warning:

case produced(year: Int)

Next, why not fix the force-casting warning once and for all?

This rule is valuable because it keeps you attentive about something that could crash your app. Force casting will work fine as long as the data is as expected, but once it’s not, your app will crash.

In PremieredOnInfo.swift, you have two instances of force casting:

let result = match.first?.value as! Substring

A safe way to avoid it is to use optional casting while providing a value with the nil-coalescing operator. This reduces the number of code changes by avoiding making the property optional and not forcing the casting. Change the two instances using the force casting to the following:

let result = match.first?.value as? Substring ?? ""

The last two warnings are in ProductionsDataProvider.swift. Between the import statements and the disabled comment, there are three vertical spaces. The rule vertical_whitespace checks that you don’t have unnecessary vertical spaces. Delete the extra two lines.

Finally, SwiftLint is complaining that loadData() is a long function. This is true, but the default value of 40 lines is too short, and we’ve decided that the maximum function body should be 70 lines. Add the following to the rules file:

function_body_length:
    warning: 70

Build the project. Finally, you have no more warnings.

But that doesn’t mean the project is in an ideal state. It’s definitely in better shape, but you can still improve it. You only fixed the violations the default rules detected. SwiftLint has more to report on this project.