Swift Best Practices
Priority: P0
Implementation Guidelines
Control Flow (Guard over If)
- Guard for Early Exit: Use
guard letover nested if statements for better readability and to unwrap optionals early. - Nested Checks: Use
guardfor precondition checks at the top of a function to reduce nested depth. - Switch Exhaustiveness: Always handle all cases; use
@unknown defaultfor freezing enums (enums from frameworks). - if-case: Use
if case .success(let value) = resultfor simple enum pattern matching.
Value Types & Immutability
- Prefer Structs: Default to struct for value semantics and thread safety. Use
classonly when reference identity or inheritance is required. - Immutability: Always default to let for all properties and constants. Use
varonly when change is required. - Modifiers: Use
finalfor all classes that are not intended to be subclassed to improve performance (static dispatch). - Static Dispatch: Favor methods in structs and
finalclasses.
Naming & Style
- Clear Intent: Prefix booleans with
is, has, or can. Example:isValid,hasErrors,canEdit. Makes boolean state clear. - API Guidelines: Follow the official Swift API Design Guidelines. Use
camelCasefor clear names andPascalCasefor types. - Protocols: Name protocols with
-able,-ible, or-ingsuffixes (e.g.,Codable,Identifiable). - Opaque Types: Use
some Vieworsome Collectionfor return types where the underlying type is internal.
Collection Performance
- Sequence API: Use
compactMap,filter, andreduceinstead of explicit for-where loops for data transformations. - Lazy Collections: Use
.lazyfor large sequences when the result is consumed partially. - Dictionaries: Use
defaultvalues in dictionary access to avoid double optional unwrapping.
Anti-Patterns
- No Pyramid of Doom: Use
guardfor early exits. - No force unwrap: Never use
!on optionals. Use??(nil-coalescing) orif let. - No global var: Avoid mutable global state. Use Singletons (accessed via
static let shared) or DI.