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?"