SwiftLint and SwiftFormat together cover 80% of recurring code-review comments. They’re great, use them.
To cover the last 20%, you can add custom rules to your SwiftLint configuration file .swiftlint.yml
. Below are some of the custom rules I developed over time.
Auto-generated Leftovers
When you use Xcode’s templates to create a new class, you’ll get some auto-generated code that you don’t need, adding noise and making it harder to find the useful code. Just delete it.
custom_rules:
auto_generated_leftovers:
regex: 'func [^\n]*\{\n(\s*super\.[^\n]*\n(\s*\/\/[^\n]*\n)*|(\s*\/\/[^\n]*\n)+)\s*\}'
message: "Delete auto-generated functions that you don't use"
Numbers Are a Code Small
You probably know that you shouldn’t put raw numbers in code, right? Only use constants and variables, right? Well, whenever I run the following rule on a code-base, I get a surprising number of warnings.
custom_rules:
numbers_smell:
regex: '(return |case |\w\(|: |\?\? |\, |== |<=? |>=? |\+= |\-= |\/= |\*= |%= |\w\.\w+ = )\(*-?\d{2,}'
message: "Numbers smell; define a constant instead."
excluded: '.*Tests/'
NSLocalizedString
Localization is not a priority in many projects, but when you suddenly need to convert all strings to localized strings – that’s a lot of work, with a good chance of missing some strings.
The following rule is not perfect, but it seems to work well enough.
custom_rules:
non_localized_string:
regex: '(?<!NSLocalizedString\(|fatalError\(|assertionFailure\(|preconditionFailure\(|assert\(false, |format: |separator: |deprecated, message: |\w|\")(?:"[^" \n]+ [^"\n]*"|"[[:upper:]][[:lower:]]+"|""".*?""")'
message: "Wrap string in NSLocalizedString()"
match_kinds: string
excluded: '.*Tests/'
Comparing to Bool
I’m not sure why anyone would do such a thing, but some people write if (isHidden == true)
instead of simply if isHidden
. I don’t even know in which language that would make sense, but definitely not Swift. Therefore:
custom_rules:
already_true:
regex: "== true"
message: "Don't compare to true, just use the bool value."
already_bool:
regex: "== false"
message: "Don't compare to false, just use !value."
Commented-out Code
If you use source-control, there is no reason to leave old commented-out code – you can always find it in your repository. Just clean it up.
custom_rules:
commented_code:
regex: '(?<!:|\/)\/\/\h*[a-z.](?!wiftlint)'
message: "Comment starting with lowercase letter - did you forget to delete old code?"
multiline_commented_code:
regex: '^\s*[a-z]'
match_kinds: comment
message: "Comment starting with lowercase letter - did you forget to delete old code?"