Clean Code in Swift: Principles and Examples for iOS/macOS

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Clean Code in Swift: Why iOS Developers Need It



Every developer has encountered a situation where old code turns into "spaghetti" after a month. In the world of Swift, where projects grow quickly, maintaining code cleanliness becomes critical. Clean Code is not just about aesthetics, but a tool that saves hours of debugging and simplifies adding new features. In this article, we will break down the key principles of Clean Code as applied to Swift, with real examples for iOS and macOS.



1. Naming: Readability First



Proper naming is the foundation of clean code. In Swift, where APIs are often self-documenting, bad names are the main source of confusion.



Bad Example:

class DataManager {    func getData() -> [String: Any] {        // ...    }}


Good Example:

class UserProfileFetcher {    func fetchUserProfile(for userID: String) -> Result<UserProfile, NetworkError> {        // ...    }}


  • Use verbs for methods (fetch, update, delete).
  • Avoid abbreviations — vc, btn, str are a thing of the past.
  • Boolean variables should read like statements: isLoggedIn, hasNetworkConnection.


2. Functions: Small and Single-Purpose



In Swift, where closures and functional programming are popular, it's easy to get carried away and write a monolithic function. The Single Responsibility Principle works 100% here.



Bad Example:

func processUserData(user: User) {    // Validation    if user.email.isEmpty { return }    // Save to CoreData    CoreDataStack.shared.save(user)    // Send to server    APIClient.shared.send(user)    // Update UI    DispatchQueue.main.async {        self.tableView.reloadData()    }}


Good Example (splitting into small functions):

func processUserData(user: User) {    guard validateUser(user) else { return }    saveUserLocally(user)    sendUserToServer(user)    updateUI()}

private func validateUser(_ user: User) -> Bool { return !user.email.isEmpty}

private func saveUserLocally(_ user: User) { CoreDataStack.shared.save(user)}

private func sendUserToServer(_ user: User) { APIClient.shared.send(user)}

private func updateUI() { DispatchQueue.main.async { self.tableView.reloadData() }}


The 20-line rule: if a function doesn't fit on the screen — break it up. Each function should do only one thing.



3. SOLID in Swift: Practical Examples



The SOLID principles are not an abstraction, but working tools. Let's break down two key ones for iOS.



Open/Closed Principle

Classes should be open for extension but closed for modification. Instead of changing a ready-made class, use protocols.



protocol PaymentProcessor {    func process(amount: Double, currency: String) -> Bool}

class ApplePayProcessor: PaymentProcessor { func process(amount: Double, currency: String) -> Bool { // Apple Pay logic return true }}

class StripeProcessor: PaymentProcessor { func process(amount: Double, currency: String) -> Bool { // Stripe logic return true }}

// Now adding a new payment method is simple — just create a new class without touching the old ones.


Liskov Substitution Principle

Subclasses should not break the parent's logic. A typical mistake is overriding a method and changing its contract.



class Vehicle {    func startEngine() {        print("Engine started")    }}

class ElectricCar: Vehicle { override func startEngine() { // Violation: el

Blogs

Book Recommendations