min()
or max()
over sorted().first
or sorted().last
SW-P1011Using sorted().first
or sorted().last
can be inefficient, as the entire collection needs to be sorted, which is not required if we only need the minimum or maximum element. This can cause performance issues, especially when dealing with large collections.
.first(where:)
over .filter { }.first
in collections SW-P1007Using .first(where:)
instead of .filter { }.first
in collections, can result in cleaner and more efficient code.
.last(where:)
over .filter { }.last
in collections SW-P1009Using .filter {}.last
to get the last element of a collection is less efficient than using .last(where:)
. The former method first iterates through the entire collection to filter the elements and then returns the last element. This is less efficient because it allocates an intermediate buffer/allocation.
contains
over range(of:) != nil
and range(of:) == nil
SW-P1012Using range(of:) != nil
and range(of:) == nil
instead of contains
can lead to slower performance and less readable code.
Array(seq)
over seq.map { $0 }
to convert a sequence into an Array SW-R1000Using the Array initializer Array(seq)
is a more concise and performant way of converting a sequence into an Array in Swift, as opposed to using seq.map { $0 }
. Here's why: Performance: When using seq.map { $0 }
to convert a sequence into an Array, the map
function creates a new array and copies all the elements from the sequence into the new array. The Array
initializer, on the other hand, creates an array with the exact same elements as the sequence, without any intermediate steps. This makes Array(seq)
more performant than seq.map { $0 }
for large sequences.
Legacy functions like arc4random()
or arc4random_uniform()
should not be used for generating random numbers. These functions are provided through imported C APIs, and depending on the platform that is executing the code, their underlying implementations can be unsafe.
TODO/FIXME comments are usually placed within the source code to indicate that there might be a scenario that is either unaccounted for or that a feature requires further enhancements. In either way, they must be addressed when and where possible to avoid unintended side-effects or breakdown.
[Type]
instead of Array<Type>
SW-C1003Using the shorthand syntactic sugar for defining arrays, i.e., []
instead of Array
, can make the code more concise and readable. Here are some reasons why:
@objc
is redundant when used with implicit Objective-C attribute SW-R1011The @objc
attribute is used to expose Swift declarations to Objective-C code. However, it can be redundant in some cases, where the declaration is already implicitly @objc
, or it's not necessary for the declaration to be exposed to
This issue highlights the redundant use of access control for property setters in Swift. If the access level of the variable and the setter are the same, it's unnecessary to specify the access level for the setter explicitly.
Unneeded break
statements are often found in switch cases in Swift. These break
statements are redundant since they are executed automatically at the end of each case block. There is no harm in using break
explicitly, but it
fatalError()
SW-R1021When invoking fatalError()
in Swift, it is essential to provide a descriptive message to help with debugging and understanding the cause of the crash. This is because fatalError()
is essentially an assertion that always fails, and the message provided helps identify the source of the failure. If a message is not provided, it can be challenging to track down the issue that caused the crash. The developer would have to rely on the stack trace, which is often not sufficient to identify the root cause of the problem.
none
SW-R1025Using "none" as a member name in an enum may create ambiguity and confusion while working with optional values. This is because Optional.none
is a reserved keyword in Swift, and using it as a member name in an enum may conflict with that. If you use "none" as a member name in an enum, it may lead to unexpected behavior when working with optional values. For example, consider the following code:
Using the fallthrough
keyword in switch statements can lead to subtle and hard-to-find bugs in Swift. The fallthrough
keyword allows the control flow to move to the next case in a switch statement. This can be useful in some cases, but it can also make the code harder to read and increase the risk of unexpected behavior.
Types that are used solely for hosting static members should be implemented as a caseless enum in Swift. By using a caseless enum, you explicitly indicate that the type should not be instantiated. This helps prevent accidental creation of instances, which can lead to unnecessary memory allocation and potential misuse of the type.
When defining enum cases in Swift, it is unnecessary and redundant to explicitly specify the enum values when they are same as the enum case name. Redundantly specifying the enum values can lead to code duplication and increase the likelihood of mistakes.
XCTFail
call should include a description of the assertion SW-R1032When a test case fails, the XCTFail call is used to indicate the failure. However, without a description, it becomes challenging to determine the specific reason for the failure. This can lead to confusion and increase debugging time, especially when multiple assertions are present in the same test case. It is recommended to always include a descriptive message when using XCTFail to provide clarity and context for failed assertions.
In Swift, setters should always access the value that is provided for the backing field. If a setter does not access this value, it is possible that the backing field contains a value other than what the user intended. This can result in unexpected behavior and is likely a mistake.
Comparing two identical operands in a binary operator can be a mistake. If two identical operands are used in a binary operator, the result is always predictable and will always be true. This can lead to unintended consequences if the code is meant to compare two different variables.
@IBOutlet
s shouldn’t be declared as weak SW-W1020By declaring @IBOutlets
as weak, you are creating a weak reference to the outlet. Weak references do not keep the referenced object alive, meaning that the outlet can be deallocated if there are no other strong references to it. This can result in unexpected crashes or undefined behavior when accessing the outlet.