- Identifier
- no_force_cast
- File name
- NoForceCastRule.swift
- Severity
- Minor
- Category
- Bad Practice
Force casting as!
should be avoided, because it could crash the program
when the type casting fails.
Although it is arguable that, in rare cases, having crashes may help developers
identify issues easier, we recommend using a guard
statement with optional casting
and then handle the failed castings gently.
let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as! MyCustomCell
// guard let cell =
// tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as? MyCustomCell
// else {
// print("Failed in casting to MyCustomCell.")
// return UITableViewCell()
// }
return cell
- Identifier
- no_forced_try
- File name
- NoForcedTryRule.swift
- Severity
- Minor
- Category
- Bad Practice
Forced-try expression try!
should be avoided, because it could crash the program
at the runtime when the expression throws an error.
We recommend using a do-catch
statement with try
operator and handle the errors
in catch
blocks accordingly; or a try?
operator with nil
-checking.
let result = try! getResult()
// do {
// let result = try getResult()
// } catch {
// print("Failed in getting result with error: \(error).")
// }
//
// or
//
// guard let result = try? getResult() else {
// print("Failed in getting result.")
// }
- Identifier
- remove_get_for_readonly_computed_property
- File name
- RemoveGetForReadOnlyComputedPropertyRule.swift
- Severity
- Minor
- Category
- Bad Practice
A computed property with a getter but no setter is known as a read-only computed property.
You can simplify the declaration of a read-only computed property by removing the get keyword and its braces.
var foo: Int {
get {
return 1
}
}
// var foo: Int {
// return 1
// }
- Identifier
- redundant_initialization_to_nil
- File name
- RedundantInitializationToNilRule.swift
- Severity
- Minor
- Category
- Bad Practice
It is redundant to initialize an optional variable to nil
,
because if you don’t provide an initial value when you declare an optional variable or property,
its value automatically defaults to nil
by the compiler.
var foo: Int? = nil // var foo: Int?
- Identifier
- redundant_if_statement
- File name
- RedundantIfStatementRule.swift
- Severity
- Minor
- Category
- Bad Practice
This rule detects three types of redundant if statements:
- then-block and else-block are returning true/false or false/true respectively;
- then-block and else-block are the same constant;
- then-block and else-block are the same variable expression.
They are usually introduced by mistake, and should be simplified or removed.
if a == b {
return true
} else {
return false
}
// return a == b
if a == b {
return false
} else {
return true
}
// return a != b
if a == b {
return true
} else {
return true
}
// return true
if a == b {
return foo
} else {
return foo
}
// return foo
- Identifier
- redundant_conditional_operator
- File name
- RedundantConditionalOperatorRule.swift
- Severity
- Minor
- Category
- Bad Practice
This rule detects three types of redundant conditional operators:
- true-expression and false-expression are returning true/false or false/true respectively;
- true-expression and false-expression are the same constant;
- true-expression and false-expression are the same variable expression.
They are usually introduced by mistake, and should be simplified or removed.
return a > b ? true : false // return a > b
return a == b ? false : true // return a != b
return a > b ? true : true // return true
return a < b ? "foo" : "foo" // return "foo"
return a != b ? c : c // return c
- Identifier
- constant_if_statement_condition
- File name
- ConstantIfStatementConditionRule.swift
- Severity
- Minor
- Category
- Bad Practice
if true { // always true
return true
}
if 1 == 0 { // always false
return false
}
if 1 != 0, true { // always true
return true
}
- Identifier
- constant_guard_statement_condition
- File name
- ConstantGuardStatementConditionRule.swift
- Severity
- Minor
- Category
- Bad Practice
guard true else { // always true
return true
}
guard 1 == 0 else { // always false
return false
}
guard 1 != 0, true else { // always true
return true
}
- Identifier
- constant_conditional_operator_condition
- File name
- ConstantConditionalOperatorConditionRule.swift
- Severity
- Minor
- Category
- Bad Practice
1 == 1 ? 1 : 0
true ? 1 : 0
false ? 1 : 0
- Identifier
- inverted_logic
- File name
- InvertedLogicRule.swift
- Severity
- Minor
- Category
- Bad Practice
if a != 0 { // if a == 0 {
i = 1 // i = -1
} else { // } else {
i = -1 // i = 1
} // }
!foo ? -1 : 1 // foo ? 1 : -1
- Identifier
- double_negative
- File name
- DoubleNegativeRule.swift
- Severity
- Minor
- Category
- Bad Practice
Logically, double negative is positive. So prefer to write positively.
!!foo // foo
!(a != b) // a == b
- Identifier
- collapsible_if_statements
- File name
- CollapsibleIfStatementsRule.swift
- Severity
- Minor
- Category
- Bad Practice
This rule detects instances where the conditions of two consecutive if statements can be combined into one in order to increase code cleanness and readability.
if (x) {
if (y) {
foo()
}
}
// depends on the situation, could be collapsed into
// if x && y { foo() }
// or
// if x, y { foo() }
- Identifier
- redundant_variable_declaration_keyword
- File name
- RedundantVariableDeclarationKeywordRule.swift
- Severity
- Minor
- Category
- Bad Practice
When the result of a function call or computed property is discarded by
a wildcard variable _
, its let
or var
keyword can be safely removed.
let _ = foo() // _ = foo()
var _ = bar // _ = bar
- Identifier
- redundant_enumcase_string_value
- File name
- RedundantEnumCaseStringValueRule.swift
- Severity
- Minor
- Category
- Bad Practice
According to Swift language reference:
For cases of a raw-value typed enumeration declaration, if the raw-value type is specified as
String
and no values are assigned to the cases explicitly, each unassigned case is implicitly assigned a string with the same text as the name of that case.
So the string literal can be omitted when it is the same as the case name.
enum Foo: String {
case a = "a" // case a
case b, c = "c" // case b, c
case d
}
- Identifier
- redundant_break_in_switch_case
- File name
- RedundantBreakInSwitchCaseRule.swift
- Severity
- Minor
- Category
- Bad Practice
According to Swift language reference:
After the code within a matched case has finished executing, the program exits from the switch statement. Program execution does not continue or “fall through” to the next case or default case.
This means in Swift, it's safe to remove the break
at the end of each switch case.
switch foo {
case 0:
print(0)
break // redundant, can be removed
case 1:
print(1)
break // redundant, can be removed
default:
break
}
- Identifier
- redundant_return_void_type
- File name
- RedundantReturnVoidTypeRule.swift
- Severity
- Minor
- Category
- Bad Practice
For functions that do not return, the -> Void
can be removed.
func foo() -> Void // func foo()
func foo() -> () // func foo()
- Identifier
- dead_code
- File name
- DeadCodeRule.swift
- Severity
- Major
- Category
- Bad Practice
Control transfer statements (break
, continue
, fallthrough
, return
, and throw
)
can change the order of program execution.
In the same scope of code block, the code after control transfer statements
is unreachable and will never be executed.
So they are considered as dead, and suggested to be removed.
for _ in 0..<10 {
if foo {
break
print("foo") // dead code, never print
}
}
while foo {
if bar {
continue
print("bar") // dead code, never print
}
}
func foo() {
if isJobDone {
return
startNewJob() // dead code, new job won't start
}
}
func foo() throws {
if isJobFailed {
throw JobError.failed
restartJob() // dead code, job won't restart
}
}