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 tough to learn and the structure is messy. This novel would take extra effort to learn. And irrespective of how good the novel is, you’ll nonetheless have combined emotions about it and the creator’s expertise.
Writing code is not any totally different. Messy and inconsistent code takes extra effort to learn. Luckily there are instruments on the market that can assist you write code that’s constant in type. Enter SwiftLint!
On this tutorial, you’ll study:
- What SwiftLint is.
- How one can set up SwiftLint and combine it into your tasks.
- A number of the coding guidelines SwiftLint checks.
- To manage which guidelines you wish to allow and disable in your mission.
- How one can create customized guidelines.
- How one can share a guidelines file throughout your totally different tasks or the staff.
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 revealed or introduced.
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. It will obtain the SPM bundle contained in the your mission folder which is required for demo functions in the course of the tutorial. Yow will discover this setting from the menu File ▸ Workspace Settings.
What Is SwiftLint?
Earlier than diving into code, you need to know a bit about SwiftLint. Whereas constructing your app, you’ll focus extra on the code itself as an alternative of on learn how to maintain the code organized. SwiftLint is all about your code group reasonably than the logic you’re implementing. For instance SwiftLint might help you to implement the utmost variety of strains 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 possible have its personal set of tips they comply with. SwiftLint helps builders to specify a set of conventions and tips. So everybody contributing to the mission follows it.
How SwiftLint Works
SwiftLint goes by way of information in your mission listing and appears for sure patterns. If it finds any, it studies them by way 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, it is advisable to do two issues:
- Set up SwiftLint in your laptop.
- 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 tasks.
There’s no proper or unsuitable, higher or worse. It’s all a matter of choice. 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 rather a lot simpler by putting in utilities you utilize in your laptop and managing any dependencies these utilities could have.
Putting in Homebrew is straightforward 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
It will set up the most recent model of SwiftLint.
Utilizing Terminal
Now that you’ve SwiftLint put in, why not attempt it?
In Terminal, navigate to your starter mission. A easy manner to do this is to sort 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.
Subsequent, sort the next into your terminal:
swiftlint
You’ll see many messages in Terminal, a few of which appear to be 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 strains are warnings and errors that SwiftLint has present in your mission. The final message will finish one thing like this:
Completed linting! Discovered 144 violations, 17 severe in 165 information.
This tells you what number of whole warnings and errors there are, what number of are severe, and what number of whole information 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 Mission 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.
While you construct the mission, it’ll run the instructions entered on this step as in the event you had been coming 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 will 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 giant textual content field beneath Shell with the next:
echo "${PROJECT_DIR}/MarvelProductions/DataProvider/ProductionsDataProvider.swift:39:7: error: I do not just like the identify of this class!"
exit 1
Be certain that to uncheck all of the checkboxes.
The purpose of this script is to point out you how one can report an error in one of many information 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 setting variable outlined by Xcode that interprets to the folder path of the mission file. This manner, it doesn’t matter you probably have the mission in your desktop or anyplace 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 point out. It may be an error, warning or observe.
- I don’t just like the identify 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 identify of this class!
and a small cursor below the primary letter of the category identify.
The final line exit 1 means there was an error from the operation and Xcode ought to fail the construct. Something aside from 0 (zero) means an error, so 1 doesn’t imply something particular.
Be happy to alter the file, line, sort of message and the message textual content and rebuild the mission. However observe the colons as a result of Xcode expects the message on this particular format to point out the message on the supply code. In any other case, an ordinary 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:/decide/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 recommended script to execute SwiftLint through Xcode. The primary line is essential when utilizing a Mac with an Apple Silicon processor. The script additionally checks whether or not you may have put in SwiftLint. In any other case, it prints a message to remind your staff members who want to put in it.
Construct the mission. You’ll see all errors and warnings reported in Xcode prefer it normally studies syntax errors.
Time to repair up these errors! However first, let’s check out how SwiftLint defines the foundations that it follows.
What Are SwiftLint Guidelines?
While 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 incorporates an enormous algorithm it will possibly detect. Not all groups have the identical tips, 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 record 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 offers 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 go, however warn you to the error.
Utilizing Guidelines File
The default file SwiftLint seems for is .swiftlint.yml subsequent to the mission file. As a result of the file identify begins with a dot, the best strategy to create it’s by way of Terminal.
Return to Terminal and make sure you’re on the trail of the starter mission. Then, sort 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 point out hidden information in Finder.
Construction of the Guidelines File
The file you created is the place you configure all the pieces about SwiftLint. You may disable a number of the guidelines which are on by default and allow others. Or you possibly can specify solely a specific algorithm to allow. The primary strategy makes use of the default guidelines specified internally in SwiftLint. These default guidelines are topic to alter in response to the model of SwiftLint. The second strategy utterly ignores all of the default guidelines and specifies solely those you need. This strategy would get pleasure from the algorithm not altering when SwiftLint is up to date.
Neither choice is best. It’s all about how you favor to manage it.
Within the guidelines file, you can too specify information and folders to disregard. For instance, you may need some third-party libraries within the mission folder or some generated information you don’t wish to cowl within the checks.
Excluded Record
The present mission installs the Nuke library through SPM which downloads to the mission listing. SwiftLint is reporting a big 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 shouldn’t be set to be within the mission listing. Try the Getting Began part of this tutorial and be sure 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.
Disabling Guidelines
One rule is essential for a mission: orphaned_doc_comment. This rule studies a violation on each remark line.
Return to the foundations file and add the next on the finish:
disabled_rules:
- orphaned_doc_comment
Save the file and construct the mission.
Now, that’s way more practical to work with.
Configuring Guidelines
Your mission nonetheless doesn’t construct because of the three errors SwiftLint is reporting. For those who’re introducing SwiftLint into a big mission a staff has been engaged on for years, you’ll have many greater than three errors. It’s not practical to utterly fail the mission at this level. It might be extra handy for you and the staff to scale back the severity of these violations from errors to warnings to unblock the entire mission. That is the place rule configurations are available.
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:
- force_cast has just one configuration potential, which is to set it to both warning or error.
-
identifier_name permits for extra configurations. The record 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 displaying as warnings. As for the one from identifier_name, it has disappeared.
Disabling Guidelines By way of Code
There’s one other strategy 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 desired guidelines utterly. Ranging from this remark till the top 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 nicely with Regex expressions and don’t apply there. Because of this it’s vital 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 Situation 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 in the event you break a URL into many strains. 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 efficacious as a result of it retains you attentive about one thing that would crash your app. Power casting will work advantageous so long as the information is as anticipated, however as soon as it’s not, your app will crash.
In PremieredOnInfo.swift, you may have two cases of pressure casting:
let end result = match.first?.worth as! Substring
A protected strategy 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 adjustments by avoiding making the property non-compulsory and never forcing the casting. Change the 2 cases utilizing the pressure casting to the next:
let end result = 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 strains.
Lastly, SwiftLint is complaining that loadData()
is an extended operate. That is true, however the default worth of 40
strains is just too brief, and we’ve determined that the utmost operate physique ought to be 70 strains. Add the next to the foundations file:
function_body_length:
warning: 70
Construct the mission. Lastly, you haven’t any extra warnings.
However that doesn’t imply the mission is in a great state. It’s undoubtedly 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 staff 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 pressure 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 []
}
Just a few of the pressure castings in ProductionYearInfo.swift are as a result of some Int
initializations are force-unwrapped. Int(:)
can produce nil
if the string handed shouldn’t be a quantity. For any cause, if the worth handed to the constructor had an alphabetical character, the produced worth could be nil
, and the pressure unwrapping would trigger a crash.
You’ll repair this utilizing the nil-coalescing operator. However you’ll attempt a trick to unravel multiple 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
.
By maintaining the enhancing cursor on the primary textual content discipline and urgent return on the keyboard, Xcode will search and gained’t apply the alternative. That is helpful if you wish to verify earlier than urgent the “Substitute all” button.
You’ll have 5 search outcomes. All have a pressure unwrapping on an Int(:)
name. Substitute all.
Construct the mission to verify 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((.+))!
seems for any textual content beginning with Int(
. As a result of the spherical brackets are precise characters utilized in common expressions, you should escape them.
The interior 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 alternative string. The remainder of the expression is the closing parentheses and the pressure unwrapping operator, )!
.
The seize group means that you can retailer the property despatched to the integer constructor and reuse this property within the new alternative string. You solely wish to concentrate on force-unwraps of Int(:)
. For those who 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 function SwiftLint helps is the flexibility to create your personal guidelines. SwiftLint treats guidelines you create the identical manner it handles its built-in guidelines. The one factor you’ll want is to create a daily expression for it.
The rule your staff needs to use is about declaring empty arrays and dictionaries. You wish to outline the sort, 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
identify: "Array/Dictionary initializer" # 2
regex: '[let,var] .+ = ([.+]())' # 3
capture_group: 1 # 4
message: "Use express sort 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:
- You begin by creating an identifier for the brand new rule and embrace all its properties beneath.
- identify: The identify for this rule.
- regex: You outline the common expression for the violation you wish to seek for.
- 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. For those who’re not utilizing seize teams, you don’t want to incorporate this property.
- message: The message you wish to present to explain the problem.
- severity: Set to error or warning.
Construct the mission to see this new rule in motion:
To repair these two warnings, you may have a direct textual content alternative 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 function that helps maintain guidelines centralized for the entire staff. The principles file doesn’t have to be beside the mission file or named .swiftlint.yml. You may transfer the file to anyplace you need in your machine. You even can retailer it on a server and go 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 basis of the person 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:/decide/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 information 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 information by clicking the Obtain supplies button on the high or backside of this tutorial.
SwiftLint is usually a highly effective device on your mission. It may additionally frustrate staff members if somebody provides guidelines as a result of extra guidelines enhance code. However this may be unsuitable. Each rule ought to have a great justification, and the staff ought to resolve collectively.
Kodeco has SwiftLint rules to comply with in all of the iOS content material throughout the web site. It’s based mostly on all the company’s coding guidelines.
In addition to checking your code, SwiftLint has extra capabilities to discover:
It’s priceless to undergo the foundations SwiftLint has at its disposal. Every rule has its rationalization of what is going to set off it and what gained’t.
We hope you loved this tutorial. When you have any questions or feedback, please be a part of the discussion board dialogue under!