Thursday, April 27, 2023
HomeProgrammingSwiftLint in Depth | Kodeco

SwiftLint in Depth | Kodeco


Constructing good apps isn’t solely about writing bug-free code. It’s additionally about writing code that requires much less effort to grasp and construct on. Think about you’re studying an impressive novel, however the font is difficult to learn and the format is messy. This novel would take extra effort to learn. And regardless of how good the novel is, you’ll nonetheless have combined emotions about it and the writer’s expertise.

Writing code isn’t any totally different. Messy and inconsistent code takes extra effort to learn. Thankfully there are instruments on the market that will help you write code that’s constant in fashion. Enter SwiftLint!

On this tutorial, you’ll study:

  • What SwiftLint is.
  • Easy methods to set up SwiftLint and combine it into your initiatives.
  • A few of the coding guidelines SwiftLint checks.
  • To manage which guidelines you need to allow and disable in your mission.
  • Easy methods to create customized guidelines.
  • Easy methods to share a guidelines file throughout your totally different initiatives or the workforce.

Getting Began

Obtain the starter mission by clicking the Obtain supplies hyperlink on the high or backside of the tutorial.

All through this tutorial, you’ll work on MarvelProductions. It lists films and TV exhibits Marvel has already printed or introduced.

Marvel Productions app running

Open the starter mission and have a look round.

Earlier than transferring ahead with the tutorial, change the workspace setting for the DerivedData folder of this workspace to be relative to the mission and never within the default location. This can obtain the SPM bundle contained in the your mission folder which is required for demo functions through the tutorial. Yow will discover this setting from the menu File ▸ Workspace Settings.

Changing DerivedData location setting

What Is SwiftLint?

Earlier than diving into code, it’s best to know a little bit about SwiftLint. Whereas constructing your app, you’ll focus extra on the code itself as an alternative of on easy methods to hold the code organized. SwiftLint is all about your code group moderately than the logic you’re implementing. For instance SwiftLint may also help you to implement the utmost variety of traces a file or a technique ought to be. This prevents writing tremendous lengthy strategies or making a file with too many courses or strategies inside it.

As you’re employed with totally different groups, every will probably have its personal set of pointers they comply with. SwiftLint helps builders to specify a set of conventions and pointers. So everybody contributing to the mission follows it.

How SwiftLint Works

SwiftLint goes by means of recordsdata in your mission listing and appears for sure patterns. If it finds any, it stories them by means of a message on the command line.

The app runs from the command line and doesn’t have any interface of its personal. So to make use of it, that you must do two issues:

  1. Set up SwiftLint in your laptop.
  2. Add a Run Script section in your construct steps of your Xcode mission which runs SwiftLint.

Putting in SwiftLint

You may have many choices to put in SwiftLint, together with CocoaPods or Homebrew. In any case, it’ll work the identical. The previous will set up it within the mission. So everybody engaged on the mission could have it whereas putting in the dependencies. The latter will set up it in your machine so you utilize it in all of your initiatives.

There’s no proper or improper, higher or worse. It’s all a matter of desire. For this tutorial, you’ll use the latter choice, Homebrew.

Putting in Homebrew

Be aware: If you have already got Homebrew put in in your machine, skip this half.

Homebrew is a bundle supervisor for utilities on macOS. It makes life lots simpler by putting in utilities you utilize in your laptop and managing any dependencies these utilities might have.

Putting in Homebrew is easy as working this command from Terminal:


/bin/bash -c "$(curl -fsSL https://uncooked.githubusercontent.com/Homebrew/set up/HEAD/set up.sh)"

Putting in SwiftLint

To put in SwiftLint with Homebrew, run this command in Terminal after putting in Homebrew.


brew set up swiftlint

This can set up the most recent model of SwiftLint.

Be aware: If you wish to set up a selected model of SwiftLint, that you must use one thing apart from Homebrew. Both obtain the model you need from SwiftLint releases on GitHub or use Mint.

Utilizing Terminal

Now that you’ve SwiftLint put in, why not attempt it?

In Terminal, navigate to your starter mission. A easy approach to try this is to kind cd (with an area after cd). Then, drag and drop the folder from Finder to the Terminal window to stick the folder path in Terminal. Then press Return to execute the command.

Drawing the starter project file on the Terminal window instead of typing the path

Subsequent, kind the next into your terminal:


swiftlint

You’ll see many messages in Terminal, a few of which seem like this:


..../MarvelProductionItem.swift:66:1: warning: Line Size Violation: Line ought to be 120 characters or much less; at the moment it has 173 characters (line_length)

These traces are warnings and errors that SwiftLint has present in your mission. The final message will finish one thing like this:


Executed linting! Discovered 144 violations, 17 severe in 165 recordsdata.

This tells you what number of complete warnings and errors there are, what number of are severe, and what number of complete recordsdata have been scanned.

That is how SwiftLint works. There’s extra, in fact, however so far as the way it’s executed and runs, that’s it!

Subsequent is to report these messages in Xcode and present you the file and line containing the violation.

Xcode Integration

Xcode permits messages from a command line operation to seem on high of supply code, like syntax errors or warnings.

Open MarvelProductions.xcworkspace within the starter mission. Choose the MarvelProductions mission file on the high of the Venture navigator. Then click on on the MarvelProductions goal and eventually choose the Construct Phases tab. Click on the small + button on the top-left so as to add a brand new section and choose New Run Script Part from the menu.

Adding a new Run Script Phase from the menu

Once you construct the mission, it’ll run the instructions entered on this step as should you had been getting into them on the command line. Xcode may even obtain messages from the executed command and embrace them within the construct log.

Be aware: You may change the order of the construct steps by dragging the brand new run script section and transferring it as much as execute earlier. This could prevent time to see outcomes from this script earlier than different operations.

Open up the brand new Run Script construct section and substitute the textual content within the massive textual content field beneath Shell with the next:


echo "${PROJECT_DIR}/MarvelProductions/DataProvider/ProductionsDataProvider.swift:39:7: error: I do not just like the title of this class!"
exit 1

The new commands entered in the new Run Script phase

Be certain that to uncheck all of the checkboxes.

The goal of this script is to indicate you how one can report an error in one of many recordsdata within the mission. Here’s what’s occurring within the script above:

  • echo: A Terminal command that prints out the string that follows it. It’s like print(:) in Swift. On this script, Xcode prints all of the textual content that follows it.
  • ${PROJECT_DIR}: An atmosphere variable outlined by Xcode that interprets to the folder path of the mission file. This manner, it doesn’t matter when you have the mission in your desktop or wherever else – the script stays the identical.
  • /MarvelProductions/DataProvider/ProductionsDataProvider.swift: The file you’re reporting an error in is ProductionsDataProvider.swift. This string is the trail of the file relative to the mission file.
  • :39:7:: The road and column quantity within the code file Xcode will mark with the message.
  • error:: The kind of message to indicate. It may be an error, warning or notice.
  • I don’t just like the title of this class!: The textual content to seem within the message.

Construct the mission. The construct operation will fail and present you an error in ProductionsDataProvider.swift with the message I do not just like the title of this class! and a small cursor below the primary letter of the category title.

An error message appearing on ProductionsDataProvider.swift

The final line exit 1 means there was an error from the operation and Xcode ought to fail the construct. Something apart from 0 (zero) means an error, so 1 doesn’t imply something particular.

Be happy to alter the file, line, kind of message and the message textual content and rebuild the mission. However notice the colons as a result of Xcode expects the message on this particular format to indicate the message on the supply code. In any other case, a regular message will seem within the construct log.

When you’ve accomplished it, substitute the script with the next to combine SwiftLint into your mission:


export PATH="$PATH:/choose/homebrew/bin"
if which swiftlint > /dev/null; then
  swiftlint
else
  echo "warning: SwiftLint not put in, obtain from https://github.com/realm/SwiftLint"
fi

That is the beneficial script to execute SwiftLint by means of Xcode. The primary line is essential when utilizing a Mac with an Apple Silicon processor. The script additionally checks whether or not you’ve got put in SwiftLint. In any other case, it prints a message to remind your workforce members who want to put in it.

Construct the mission. You’ll see all errors and warnings reported in Xcode prefer it often stories syntax errors.

Build failed with 17 errors and 124 warnings

Time to repair up these errors! However first, let’s check out how SwiftLint defines the foundations that it follows.

What Are SwiftLint Guidelines?

Once you ran SwiftLint earlier, it reported a number of violations within the starter mission. You didn’t configure or specify something about what violations it ought to catch. So why did it catch these violations?

SwiftLint accommodates an enormous algorithm it could possibly detect. Not all groups have the identical pointers, so these guidelines are opt-in solely. However SwiftLint has some guidelines at its disposal, that are what it applies within the mission.

One rule producing many warnings is orphaned_doc_comment. Yow will discover extra about it in the documentation.

Additionally, the official documentation has the listing of enabled guidelines by default and those you possibly can allow your self. You’ll see the way you try this shortly.

Warnings and Errors

Discover that some violations are errors and others are warnings. SwiftLint provides you management over which guidelines are errors and that are simply warnings. An error would fail the construct whereas a warning would let the construct cross, however warn you to the error.

Utilizing Guidelines File

The default file SwiftLint appears to be like for is .swiftlint.yml subsequent to the mission file. As a result of the file title begins with a dot, the best method to create it’s by means of Terminal.

Return to Terminal and make sure you’re on the trail of the starter mission. Then, kind the next command:


contact .swiftlint.yml

This creates a hidden file named .swiftlint.yml. To view the file, go to the mission folder in Finder. Press Shift-Command-, to indicate hidden recordsdata in Finder.

Starter project with the hidden file .swiftlint.yml

Construction of the Guidelines File

The file you created is the place you configure all the pieces about SwiftLint. You may disable among the guidelines which are on by default and allow others. Or you possibly can specify solely a specific algorithm to allow. The primary method makes use of the default guidelines specified internally in SwiftLint. These default guidelines are topic to alter in keeping with the model of SwiftLint. The second method utterly ignores all of the default guidelines and specifies solely those you need. This method would get pleasure from the algorithm not altering when SwiftLint is up to date.

Neither choice is healthier. It’s all about how you favor to manage it.

Within the guidelines file, you can too specify recordsdata and folders to disregard. For instance, you might need some third-party libraries within the mission folder or some generated recordsdata you don’t need to cowl within the checks.

Excluded Listing

The present mission installs the Nuke library by way of SPM which downloads to the mission listing. SwiftLint is reporting a major variety of violations in it.

Be aware: If you don’t discover any violations from inside Nuke then it’s as a result of your DerivedData folder is just not set to be within the mission listing. Take a look at the Getting Began part of this tutorial and ensure you adopted the directions there.

Open .swiftlint.yml, which ought to be empty, and enter the next:


excluded:
  - DerivedData

Save the file, then construct the mission.

Discover that the variety of violations dropped considerably! You now have solely the SwiftLint violations out of your mission’s code.

Number of errors and warnings dropped after excluding the DerivedData folder

Disabling Guidelines

One rule is essential for a mission: orphaned_doc_comment. This rule stories a violation on each remark line.

Return to the foundations file and add the next on the finish:


disabled_rules:
  - orphaned_doc_comment

Updated rules file with excluded DerivedData folder and excluded rules

Save the file and construct the mission.

Now, that’s far more life like to work with.

Configuring Guidelines

Your mission nonetheless doesn’t construct because of the three errors SwiftLint is reporting. When you’re introducing SwiftLint into a big mission a workforce has been engaged on for years, you’ll have many greater than three errors. It’s not life like to utterly fail the mission at this level. It will be extra handy for you and the workforce to cut back the severity of these violations from errors to warnings to unblock the entire mission. That is the place rule configurations are available in.

The 2 error-generating guidelines are force_cast and identifier_name. You may configure guidelines to match your wants.

On the finish of the foundations file, add the next:


force_cast: warning # 1

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

The configuration you added consists of two elements:

  1. force_cast has just one configuration attainable, which is to set it to both warning or error.
  2. identifier_name permits for extra configurations. The listing of variable names permits them to exclude. The mission makes use of i, however the others are additionally widespread variable names that break the rule however are acceptable to us.

Construct the mission, and now it should lastly succeed. The 2 errors from force_cast are exhibiting as warnings. As for the one from identifier_name, it has disappeared.

Disabling Guidelines By Code

There’s one other method to disable a rule. You may ignore a rule by including a remark earlier than the code block that produces the violation. For instance:


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

This disables the required guidelines utterly. Ranging from this remark till the tip of the file or till you allow them once more:


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

There’s additionally the choice to disable a rule that’s showing within the subsequent line and the following line solely:


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

But when the rule isn’t triggered within the subsequent line, SwiftLint will warn that this disable is pointless. This may be helpful so that you don’t fear about re-enabling the rule once more.

Within the starter mission, you’ll discover a few SwiftLint disables. These guidelines didn’t play effectively with Regex expressions and don’t apply there. Because of this it’s necessary to grasp the foundations and know once they make sense and once they don’t.

Fixing the Violations

Virtually each time, the message from SwiftLint describes why there was a violation.

For instance, discover the warning within the Problem navigator:


Comma Spacing Violation: There ought to be no house earlier than and one after any comma. (comma)

Faucet this warning. In ProductionsListView.swift, you’ll see there’s an area between MarvelProductionItem.pattern() and the comma within the first two objects. Take away these pointless areas:


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

Construct the mission. These warnings have disappeared!

Subsequent is the warning for line_length. The road inflicting this warning in MarvelProductionItem.swift is:


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

It is a prolonged line, however it may be complicated should you break a URL into many traces. For that, configure line_length to disregard URLs. Add the next rule configuration on the finish of the foundations file:


line_length:
  ignores_urls: true
  ignores_function_declarations: true
  ignores_comments: true

This ignores the road size rule for URLs, operate declarations and feedback.

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


case produced(12 months : Int)

The colon rule checks that there’s no pointless house earlier than the colon and just one house after it. As you see within the line talked about, there’s an area between the 12 months and the colon. Eradicating this house resolves the warning:


case produced(12 months: Int)

Subsequent, why not repair the force-casting warning as soon as and for all?

This rule is effective as a result of it retains you attentive about one thing that would crash your app. Pressure casting will work high-quality so long as the info is as anticipated, however as soon as it’s not, your app will crash.

In PremieredOnInfo.swift, you’ve got two cases of power casting:


let consequence = match.first?.worth as! Substring

A protected method to keep away from it’s to make use of non-compulsory casting whereas offering a price with the nil-coalescing operator. This reduces the variety of code modifications by avoiding making the property non-compulsory and never forcing the casting. Change the 2 cases utilizing the power casting to the next:


let consequence = match.first?.worth as? Substring ?? ""

The final two warnings are in ProductionsDataProvider.swift. Between the import statements and the disabled remark, there are three vertical areas. The rule vertical_whitespace checks that you simply don’t have pointless vertical areas. Delete the additional two traces.

Lastly, SwiftLint is complaining that loadData() is an extended operate. That is true, however the default worth of 40 traces is simply too quick, and we’ve determined that the utmost operate physique ought to be 70 traces. Add the next to the foundations file:


function_body_length:
    warning: 70

Construct the mission. Lastly, you don’t have any extra warnings.

However that doesn’t imply the mission is in an excellent state. It’s positively in higher form, however you possibly can nonetheless enhance it. You solely fastened the violations the default guidelines detected. SwiftLint has extra to report on this mission.

Enabling Extra Guidelines

Your workforce has agreed so as to add a number of extra guidelines on high of the defaults and never all of them with the default configurations of SwiftLint:

Add the next to the foundations file:


opt_in_rules:
  - indentation_width
  - force_unwrapping
  - redundant_type_annotation
  - force_try
  - operator_usage_whitespace

indentation_width:
  indentation_width: 2

Construct the mission. You see eight new warnings. Just one is about indentation. The remainder are due to power unwrapping.

Let’s repair the indentation one first. Faucet the indentation warning to open ProductionsDataProvider.swift. Go to the warning there, then align return [] with the catch above it:


} catch {
  return []
}

A number of of the power castings in ProductionYearInfo.swift are as a result of some Int initializations are force-unwrapped. Int(:) can produce nil if the string handed is just not a quantity. For any purpose, if the worth handed to the constructor had an alphabetical character, the produced worth could be nil, and the power unwrapping would trigger a crash.

You’ll repair this utilizing the nil-coalescing operator. However you’ll attempt a trick to resolve a couple of warning with a single search and substitute, utilizing common expressions.

From the mission navigator column, choose the Discover tab. Change Discover to Substitute and from Textual content to Common Expression. Within the first textual content discipline, enter Int((.+))! and in the second, enter Int($1) ?? 0.

Using a regular expression to change multiple code instances together

By retaining the modifying cursor on the primary textual content discipline and urgent return on the keyboard, Xcode will search and gained’t apply the substitute. That is helpful if you wish to test earlier than urgent the “Substitute all” button.

You’ll have 5 search outcomes. All have a power unwrapping on an Int(:) name. Substitute all.

Construct the mission to ensure all the pieces is OK. The construct succeeds, and you’ve got solely two warnings left. How did this regex magic work?

The expression you entered Int((.+))! appears to be like for any textual content beginning with Int(. As a result of the spherical brackets are precise characters utilized in common expressions, you need to escape them.

The internal set of parentheses is a seize group. The matched expression inside is saved for later use, and also you entry it with $1, which you entered within the substitute string. The remainder of the expression is the closing parentheses and the power unwrapping operator, )!.

The seize group permits you to retailer the property despatched to the integer constructor and reuse this property within the new substitute string. You solely need to concentrate on force-unwraps of Int(:). When you seek for )! solely throughout the mission, you’ll change locations you shouldn’t.

As for the final two warnings, discover the primary in PremieredOnInfo.swift and substitute the offending code with:


let date = formatter.date(from: dateString) ?? Date()

Then discover the second in ProductionItemView.swift and substitute the offending code with:


Textual content("(String(format: "%.1f", productionItem.imdbRating ?? 0))")

All of the warnings are gone!

Make Your Personal Guidelines

One other cool characteristic SwiftLint helps is the flexibility to create your personal guidelines. SwiftLint treats guidelines you create the identical approach it handles its built-in guidelines. The one factor you’ll want is to create a daily expression for it.

The rule your workforce needs to use is about declaring empty arrays and dictionaries. You need to outline the kind, and it shouldn’t depend on inference:


// Not OK
var array = [Int]()
var dict = [String: Int]()

// OK
var array: [Int] = []
var dict: [String: Int] = [:]

Add the next to the foundations file:


custom_rules:
  array_constructor: # 1
    title: "Array/Dictionary initializer" # 2
    regex: '[let,var] .+ = ([.+]())' # 3
    capture_group: 1 # 4
    message: "Use express kind annotation when initializing empty arrays and dictionaries" # 5
    severity: warning # 6

custom_rules is one other part within the guidelines file the place you possibly can declare your personal algorithm.

Here’s a step-by-step description of the above customized rule:

  1. You begin by creating an identifier for the brand new rule and embrace all its properties beneath.
  2. title: The title for this rule.
  3. regex: You outline the common expression for the violation you need to seek for.
  4. capture_group: If a part of the common expression match is the place the violation is and also you’re utilizing seize teams to concentrate on it, you specify the variety of the seize group right here. When you’re not utilizing seize teams, you don’t want to incorporate this property.
  5. message: The message you need to present to explain the difficulty.
  6. severity: Set to error or warning.

Construct the mission to see this new rule in motion:

The new custom rule showing two warnings in Xcode

To repair these two warnings, you’ve got a direct textual content substitute for:


// In ProductionsDataProvider.swift
var marvelProductions = [MarvelProductionItem]()

// In ProductionsListView.swift
var productionsList = [MarvelProductionItem]()

To:


var marvelProductions: [MarvelProductionItem] = []
var productionsList: [MarvelProductionItem] = []

Distant Guidelines

SwiftLint has an superior characteristic that helps hold guidelines centralized for the entire workforce. The foundations file doesn’t should be beside the mission file or named .swiftlint.yml. You may transfer the file to wherever you need in your machine. You even can retailer it on a server and cross its path as an argument to the swiftlint command:


swiftlint --config [yml file path or url]

Why not give it a attempt?

Open Terminal and navigate to your mission’s path. Then run this command:


mv .swiftlint.yml ~/swiftlintrules.yml

This strikes .swiftlint.yml from the present listing to the foundation of the consumer folder and renames the file to swiftlintrules.yml.

Return to your mission in Xcode and replace the run script to the next:


export PATH="$PATH:/choose/homebrew/bin"
if which swiftlint > /dev/null; then
  swiftlint --config ~/swiftlintrules.yml
else
  echo "warning: SwiftLint not put in, obtain from https://github.com/realm/SwiftLint"
fi

Construct the mission. Sadly, it’ll give some warnings and errors. Don’t panic. Recordsdata reporting violations are from the code recordsdata within the folder you excluded earlier.

Within the new guidelines file, change the exclude part to the next:


excluded:
  - ${PWD}/DerivedData

All you probably did was have the exclude folders with a full path. PWD, or Print Working Listing, interprets to the mission listing when Xcode runs the command.

Construct the mission once more. It’ll succeed. :]

The place to Go From Right here?

You may obtain the finished mission recordsdata by clicking the Obtain supplies button on the high or backside of this tutorial.

SwiftLint could be a highly effective software to your mission. It will possibly additionally frustrate workforce members if somebody provides guidelines as a result of extra guidelines enhance code. However this may be improper. Each rule ought to have justification, and the workforce ought to resolve collectively.

Kodeco has SwiftLint guidelines to comply with in all of the iOS content material throughout the web site. It’s primarily based on all the corporate’s coding pointers.

Moreover checking your code, SwiftLint has extra capabilities to discover:

It’s worthwhile to undergo the foundations SwiftLint has at its disposal. Every rule has its rationalization of what’s going to set off it and what gained’t.

We hope you loved this tutorial. When you have any questions or feedback, please be part of the discussion board dialogue beneath!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments