Skip to content

Latest commit

 

History

History
674 lines (505 loc) · 10.9 KB

BadPractice.md

File metadata and controls

674 lines (505 loc) · 10.9 KB

Bad Practice Rules

No Force Cast

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.

Examples:
Example 1
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

No Forced Try

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.

Examples:
Example 1
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.")
// }

Remove Get For Read-Only Computed Property

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.

Examples:
Example 1
var foo: Int {
  get {
    return 1
  }
}

// var foo: Int {
//   return 1
// }

Redundant Initialization to Nil

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.

Examples:
Example 1
var foo: Int? = nil // var foo: Int?

Redundant If Statement

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.

Examples:
Example 1
if a == b {
  return true
} else {
  return false
}
// return a == b
Example 2
if a == b {
  return false
} else {
  return true
}
// return a != b
Example 3
if a == b {
  return true
} else {
  return true
}
// return true
Example 4
if a == b {
  return foo
} else {
  return foo
}
// return foo

Redundant Conditional Operator

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.

Examples:
Example 1
return a > b ? true : false // return a > b
Example 2
return a == b ? false : true // return a != b
Example 3
return a > b ? true : true // return true
Example 4
return a < b ? "foo" : "foo" // return "foo"
Example 5
return a != b ? c : c // return c

Constant If Statement Condition

Identifier
constant_if_statement_condition
File name
ConstantIfStatementConditionRule.swift
Severity
Minor
Category
Bad Practice
Examples:
Example 1
if true { // always true
  return true
}
Example 2
if 1 == 0 { // always false
  return false
}
Example 3
if 1 != 0, true { // always true
  return true
}

Constant Guard Statement Condition

Identifier
constant_guard_statement_condition
File name
ConstantGuardStatementConditionRule.swift
Severity
Minor
Category
Bad Practice
Examples:
Example 1
guard true else { // always true
  return true
}
Example 2
guard 1 == 0 else { // always false
  return false
}
Example 3
guard 1 != 0, true else { // always true
  return true
}

Constant Conditional Operator Condition

Identifier
constant_conditional_operator_condition
File name
ConstantConditionalOperatorConditionRule.swift
Severity
Minor
Category
Bad Practice
Examples:
Example 1
1 == 1 ? 1 : 0
Example 2
true ? 1 : 0
Example 3
false ? 1 : 0

Inverted Logic

Identifier
inverted_logic
File name
InvertedLogicRule.swift
Severity
Minor
Category
Bad Practice
Examples:
Example 1
if a != 0 {  // if a == 0 {
  i = 1      //   i = -1
} else {     // } else {
  i = -1     //   i = 1
}            // }
Example 2
!foo ? -1 : 1  // foo ? 1 : -1

Double Negative

Identifier
double_negative
File name
DoubleNegativeRule.swift
Severity
Minor
Category
Bad Practice

Logically, double negative is positive. So prefer to write positively.

Examples:
Example 1
!!foo // foo
Example 2
!(a != b) // a == b

Collapsible If Statements

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.

Examples:
Example 1
if (x) {
  if (y) {
    foo()
  }
}
// depends on the situation, could be collapsed into
// if x && y { foo() }
// or
// if x, y { foo() }

Redundant Variable Declaration Keyword

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.

Examples:
Example 1
let _ = foo() // _ = foo()
Example 2
var _ = bar // _ = bar

Redundant Enum-Case String Value

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.

Examples:
Example 1
enum Foo: String {
  case a = "a"    // case a
  case b, c = "c" // case b, c
  case d
}

Redundant Break In Switch Case

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.

Examples:
Example 1
switch foo {
case 0:
  print(0)
  break        // redundant, can be removed
case 1:
  print(1)
  break        // redundant, can be removed
default:
  break
}

Redundant Return Void Type

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.

Examples:
Example 1
func foo() -> Void // func foo()
Example 2
func foo() -> () // func foo()

Dead Code

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.

Examples:
Example 1
for _ in 0..<10 {
  if foo {
    break
    print("foo") // dead code, never print
  }
}
Example 2
while foo {
  if bar {
    continue
    print("bar") // dead code, never print
  }
}
Example 3
func foo() {
  if isJobDone {
    return
    startNewJob() // dead code, new job won't start
  }
}
Example 4
func foo() throws {
  if isJobFailed {
    throw JobError.failed
    restartJob() // dead code, job won't restart
  }
}