← Swift EnglishChapter 13 of 13

Best Practices

## Learning Objectives - Follow Swift style guidelines - Write clean, maintainable code - Use Xcode effectively - Master Swift idioms ## Naming Conventions ### Types and Protocols ```swift // Use PascalCase for types and protocols struct UserProfile {} class NetworkManager {} protocol DataSource {} enum HttpMethod {} // Protocol names describe behavior protocol Reader {} protocol Writer {} ``` ### Variables and Functions ```swift // Use camelCase for variables and functions let userName = "Alice" var isAuthenticated = false func fetchUser() {} func calculateTotal() {} ``` ### Constants ```swift // Constants at module level use camelCase let maxRetryCount = 3 let defaultTimeout: TimeInterval = 30 // But enum cases use camelCase enum Result { case success case failure } ``` ### Private Details ```swift class User { // Public var name: String // Private - underscore prefix is optional private var _cachedData: String? private var internalId: UUID? } ``` ## Code Organization ### File Structure ```swift // 1. Imports import Foundation import UIKit // 2. Class/Struct declaration // 3. Properties // 4. Initialization // 5. Methods // 6. Extensions // 7. Private helpers ``` ### Protocol Conformance ```swift class MyViewController: UIViewController { // Put protocol conformance in extension } extension MyViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } } extension MyViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // Handle } } ``` ## Swift Idioms ### Prefer let over var ```swift // Good let name = "Alice" let count = items.count let filtered = items.filter { $0 > 0 } // When mutability needed var mutable = [1, 2, 3] mutable.append(4) ``` ### Prefer guard over if let ```swift // Good func process(name: String?) { guard let name = name else { return } // Use name here } // Avoid nesting func process(name: String?) { if let name = name { if name.count > 0 { // Deep nesting - avoid this } } } ``` ### Use Trailing Closures ```swift // Good numbers.map { $0 * 2 } URLSession.shared.dataTask(with: url) { data, _, _ in // Handle }.resume() ``` ### Default Values ```swift // Use nil coalescing let displayName = user.name ?? "Anonymous" // Or default parameter func greet(_ name: String = "World") { print("Hello, \(name)!") } ``` ## Error Handling ### Prefer Throws over Optionals ```swift // Good - when failure has meaning func parseJSON(_ data: Data) throws -> [String: Any] { guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { throw ParseError.invalidFormat } return json } // Use try? when failure doesn't need details if let _ = try? validate(email) { // Valid } ``` ### Result Type for Callbacks ```swift func fetchUser(completion: @escaping (Result) -> Void) { // Success completion(.success(user)) // Failure completion(.failure(NetworkError.noConnection)) } ``` ## Access Control ### Minimize Exposure ```swift // Good - expose only what's needed public class APIClient { private let baseURL: URL private var cachedResponses: [URL: Data] = [:] } // Avoid class Person { var name: String = "" // Public by default var age: Int = 0 // Should be private? var ssn: String = "" // Definitely private } ``` ### Prefer private to fileprivate ```swift class MyClass { // private - only accessible within this class private var helper: Helper // fileprivate - only within same file fileprivate var sharedState: String = "" } ``` ## Optionals ### Safe Unwrapping ```swift // Good if let value = optional { use(value) } // Better for early exit func process() { guard let value = optional else { return } use(value) } // Nil coalescing for defaults let displayName = user.name ?? "Anonymous" ``` ### Avoid Force Unwrap ```swift // Bad let name = optional! // Good alternatives if let name = optional { } guard let name = optional else { } let name = optional ?? "default" ``` ## Performance ### Value Types When Appropriate ```swift // Use struct for simple data struct Point { var x: Double var y: Double } // Use class for shared identity class Person { var name: String // Shared across app } ``` ### Lazy Properties ```swift class DataImporter { // Heavy operation only when needed lazy var data: Data = { return loadHeavyData() }() } ``` ### Avoid Retain Cycles ```swift // Use weak for delegates weak var delegate: MyDelegate? // Use capture lists in closures someCall { [weak self] result in self?.handle(result) } ``` ## Testing ### Dependency Injection ```swift // Good - testable class NetworkService { let session: URLSession init(session: URLSession = .shared) { self.session = session } } // Testable with mock let mockSession = MockURLSession() let service = NetworkService(session: mockSession) ``` ### Protocol-Oriented Design ```swift protocol StorageProtocol { func save(_ data: Data) throws func load() throws -> Data } class FileStorage: StorageProtocol { } class UserDefaultsStorage: StorageProtocol { } ``` ## Documentation ### Comments ```swift // Single line for brief explanation /* Multi-line for longer explanation or detailed comments */ /** Documentation comment (used by Xcode) */ ``` ### MARK Comments ```swift class MyClass { // MARK: - Properties var name: String // MARK: - Initialization init() { } // MARK: - Public Methods func publicMethod() { } // MARK: - Private Methods private func privateMethod() { } } ``` ## Xcode Tips ### Keyboard Shortcuts | Action | Shortcut | |--------|----------| | Run | Cmd+R | | Build | Cmd+B | | Clean | Cmd+Shift+K | | Find | Cmd+F | | Replace | Cmd+Alt+F | | Go to Definition | Cmd+Click | | Auto-indent | Ctrl+I | | Comment | Cmd+/ | ### Navigation | Action | Shortcut | |--------|----------| | Open Quickly | Cmd+Shift+O | | Navigator | Cmd+0 | | Assistant Editor | Cmd+Alt+Enter | | Open in Tab | Cmd+Enter | ### Refactoring - Cmd+Shift+E: Refactor - Extract Method: Select code, right-click > Refactor - Rename: Ctrl+Cmd+E ## Common Patterns ### Singleton ```swift final class Singleton { static let shared = Singleton() private init() { // Private initialization } } ``` ### Factory Method ```swift class Button { func createButton(style: ButtonStyle) -> UIButton { let button = UIButton(type: .system) button.setTitle(style.title, for: .normal) return button } } ``` ### Builder Pattern ```swift class UserBuilder { private var name: String = "" private var age: Int = 0 func setName(_ name: String) -> UserBuilder { self.name = name return self } func setAge(_ age: Int) -> UserBuilder { self.age = age return self } func build() -> User { return User(name: name, age: age) } } ``` ## Summary - Use PascalCase for types, camelCase for variables - Prefer `let` over `var`, `struct` over `class` when appropriate - Use `guard` for early exit and optional unwrapping - Minimize exposure with proper access control - Avoid force unwrapping and force casts - Use protocols for abstraction and testing - Document with MARK comments and Swift documentation - Learn Xcode shortcuts for productivity - Write testable code with dependency injection

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →