Files
2025-11-29 18:17:22 +08:00

14 KiB

iOS Naming Conventions Examples

Comprehensive examples of good and bad naming patterns in Swift.

Classes and Types

Good Examples

// View Controllers
class PaymentViewController: UIViewController { }
class TransactionListViewController: UIViewController { }
class RefundConfirmationViewController: UIViewController { }

// ViewModels
class PaymentViewModel: BaseViewModel<PaymentState> { }
class StoresViewModel: BaseViewModel<StoresState> { }
class TransactionHistoryViewModel: BaseViewModel<TransactionHistoryState> { }

// Use Cases
protocol PaymentUseCase { }
class PaymentUseCaseImpl: PaymentUseCase { }
protocol RefundRequestUseCase { }

// Repositories
protocol PaymentRepository { }
class PaymentRepositoryImpl: PaymentRepository { }

// Models
struct Transaction { }
struct PaymentRequest { }
struct RefundRequest { }

// Enums
enum PaymentMethod { }
enum TransactionStatus { }
enum RefundRequestError: Error { }

Bad Examples

// Too abbreviated
class PayVC: UIViewController { }           // → PaymentViewController
class RefReqVM { }                          // → RefundRequestViewModel
class TrxRepo { }                           // → TransactionRepository

// Too generic
class Manager { }                           // → PaymentManager or specific purpose
class Helper { }                            // → ValidationHelper or specific purpose
class Util { }                              // → DateFormatter or specific utility

// Missing suffixes
class Payment { }                           // → PaymentViewModel or PaymentUseCase
class Transaction { }                       // If it's a ViewModel → TransactionViewModel

Variables and Properties

Good Examples

class PaymentViewModel {
    // State properties - descriptive
    let paymentAmount = BehaviorRelay<String>(value: "")
    let selectedPaymentMethod = BehaviorRelay<PaymentMethod?>(value: nil)
    let transactionResult = BehaviorRelay<TransactionResult?>(value: nil)

    // Boolean properties - with prefixes
    let isProcessingPayment = BehaviorRelay<Bool>(value: false)
    let hasNetworkConnection = BehaviorRelay<Bool>(value: true)
    let shouldShowError = BehaviorRelay<Bool>(value: false)
    let canSubmitPayment = BehaviorRelay<Bool>(value: false)

    // Collections - plural
    let transactions = BehaviorRelay<[Transaction]>(value: [])
    let errorMessages = BehaviorRelay<[String]>(value: [])
    let availablePaymentMethods = BehaviorRelay<[PaymentMethod]>(value: [])

    // Dependencies - full names
    private let paymentUseCase: PaymentUseCase
    private let validationService: ValidationService
    private let disposeBag = DisposeBag()
}

Bad Examples

class PaymentViewModel {
    // Abbreviated
    let amt = BehaviorRelay<String>(value: "")           // → paymentAmount
    let pmtMethod = BehaviorRelay<PaymentMethod?>(value: nil)  // → paymentMethod
    let trxResult = BehaviorRelay<TransactionResult?>(value: nil)  // → transactionResult

    // Generic/meaningless
    let flag = BehaviorRelay<Bool>(value: false)         // → isProcessing
    let data = BehaviorRelay<[Any]>(value: [])           // → transactions
    let temp = BehaviorRelay<String>(value: "")          // → What is this?

    // Boolean without prefix
    let loading: Bool                                     // → isLoading
    let valid: Bool                                       // → isValid
    let enabled: Bool                                     // → isEnabled

    // Single letter
    let x = 0                                             // → transactionCount
    let a = amount                                        // → paymentAmount

    // Inconsistent abbreviations
    let paymentUC: PaymentUseCase                        // → paymentUseCase
}

Functions and Methods

Good Examples

class TransactionViewModel {
    // Actions - verb-based, descriptive
    func loadTransactions() { }
    func refreshTransactionList() { }
    func filterTransactionsByDate(from startDate: Date, to endDate: Date) { }
    func processRefundRequest(for transactionId: String) { }
    func validatePaymentAmount(_ amount: String) -> Bool { }

    // Queries - return information
    func getTransaction(by id: String) -> Transaction? { }
    func calculateTotalAmount(for transactions: [Transaction]) -> Double { }
    func hasUnprocessedTransactions() -> Bool { }
    func isValidPaymentAmount(_ amount: String) -> Bool { }

    // State handlers - clear purpose
    func handlePaymentSuccess(_ result: PaymentResult) { }
    func handlePaymentError(_ error: Error) { }
    func handleNetworkConnectionLost() { }

    // Setup/Configuration - clear intent
    func setupUI() { }
    func configureTableView() { }
    func bindViewModel() { }
}

Bad Examples

class TransactionViewModel {
    // Too vague
    func doSomething() { }                    // → processRefundRequest()
    func process() { }                        // Process what? → processPayment()
    func get() { }                            // Get what? → getTransactions()
    func handle() { }                         // Handle what? → handleError()
    func go() { }                             // Go where? → navigateToDetails()

    // Noun-based instead of verb-based
    func transaction() { }                    // → loadTransaction() or getTransaction()
    func payment() { }                        // → processPayment()

    // Abbreviated
    func procPmt() { }                        // → processPayment()
    func getTrx() { }                         // → getTransaction()
    func valAmt(_ amt: String) { }            // → validateAmount(_ amount: String)
}

IBOutlets

Good Examples

class PaymentViewController: UIViewController {
    // Text fields - with TextField suffix
    @IBOutlet weak var paymentAmountTextField: UITextField!
    @IBOutlet weak var merchantCodeTextField: UITextField!
    @IBOutlet weak var notesTextField: UITextField!

    // Labels - with Label suffix
    @IBOutlet weak var currencyLabel: UILabel!
    @IBOutlet weak var totalAmountLabel: UILabel!
    @IBOutlet weak var errorMessageLabel: UILabel!

    // Buttons - with Button suffix
    @IBOutlet weak var confirmPaymentButton: UIButton!
    @IBOutlet weak var cancelButton: UIButton!
    @IBOutlet weak var submitButton: UIButton!

    // Tables and collections - with TableView/CollectionView suffix
    @IBOutlet weak var transactionTableView: UITableView!
    @IBOutlet weak var storesCollectionView: UICollectionView!

    // Other views - with type suffix
    @IBOutlet weak var loadingIndicator: UIActivityIndicatorView!
    @IBOutlet weak var headerView: UIView!
    @IBOutlet weak var footerContainerView: UIView!
    @IBOutlet weak var paymentMethodSegmentedControl: UISegmentedControl!
}

Bad Examples

class PaymentViewController: UIViewController {
    // Missing type suffix
    @IBOutlet weak var amount: UITextField!        // → amountTextField
    @IBOutlet weak var currency: UILabel!          // → currencyLabel
    @IBOutlet weak var confirm: UIButton!          // → confirmButton

    // Abbreviated
    @IBOutlet weak var lbl: UILabel!               // → titleLabel
    @IBOutlet weak var btn: UIButton!              // → submitButton
    @IBOutlet weak var txtField: UITextField!      // → amountTextField

    // Too generic
    @IBOutlet weak var table: UITableView!         // → transactionTableView
    @IBOutlet weak var view: UIView!               // → headerView
    @IBOutlet weak var loading: UIActivityIndicatorView!  // → loadingIndicator
}

Test Naming

Good Examples

class PaymentViewModelTests: XCTestCase {
    // Format: test[MethodName]_[Scenario]_[ExpectedResult]

    func testProcessPayment_WithValidAmount_CompletesSuccessfully() { }
    func testProcessPayment_WithEmptyAmount_ShowsValidationError() { }
    func testProcessPayment_WithNetworkError_ShowsErrorState() { }
    func testLoadTransactions_WithCachedData_ReturnsDataImmediately() { }
    func testRefundRequest_WhenAmountExceedsTransaction_Fails() { }

    func testValidateAmount_BelowMinimum_ReturnsFalse() { }
    func testValidateAmount_AboveMaximum_ReturnsFalse() { }
    func testValidateAmount_ValidRange_ReturnsTrue() { }

    func testSubmitRefund_WithValidData_UpdatesStateToSuccess() { }
    func testSubmitRefund_WithInvalidData_UpdatesStateToError() { }
}

Bad Examples

class PaymentViewModelTests: XCTestCase {
    func test1() { }                           // Meaningless number
    func testPayment() { }                     // Too vague
    func testError() { }                       // What error scenario?
    func testStuff() { }                       // Meaningless
    func test_payment_works() { }              // snake_case (wrong)
}

Complete Class Examples

Well-Named Class

class PaymentProcessingViewModel: BaseViewModel<PaymentState> {
    // Dependencies - full, descriptive names
    private let paymentUseCase: PaymentUseCase
    private let validationService: ValidationService
    private let disposeBag = DisposeBag()

    // Input properties - clear, descriptive
    let paymentAmount = BehaviorRelay<String>(value: "")
    let selectedMerchantId = BehaviorRelay<String?>(value: nil)
    let additionalNotes = BehaviorRelay<String>(value: "")

    // State properties - boolean with prefixes
    let isProcessingPayment = BehaviorRelay<Bool>(value: false)
    let hasValidPaymentAmount = BehaviorRelay<Bool>(value: false)
    let shouldEnableSubmitButton = BehaviorRelay<Bool>(value: false)

    // Output properties - descriptive
    let paymentResult = BehaviorRelay<PaymentResult?>(value: nil)
    let errorMessage = BehaviorRelay<String?>(value: nil)

    // Initializer - parameter names match properties
    init(paymentUseCase: PaymentUseCase, validationService: ValidationService) {
        self.paymentUseCase = paymentUseCase
        self.validationService = validationService
        super.init()
        setupValidation()
    }

    // Methods - verb-based, descriptive
    func processPaymentRequest() { }
    func validatePaymentAmount() -> Bool { }
    func clearPaymentForm() { }
    func handlePaymentSuccess(_ result: PaymentResult) { }
    func handlePaymentError(_ error: Error) { }

    private func setupValidation() { }
    private func updateSubmitButtonState() { }
}

Poorly Named Class

class PaymentVM: BaseViewModel<PaymentState> {  // Abbreviated
    // Abbreviated dependencies
    private let pmtUC: PaymentUseCase            // → paymentUseCase
    private let valService: ValidationService    // → validationService
    private let bag = DisposeBag()               // → disposeBag

    // Abbreviated/unclear properties
    let amt = BehaviorRelay<String>(value: "")   // → paymentAmount
    let mid = BehaviorRelay<String?>(value: nil) // → merchantId
    let notes = BehaviorRelay<String>(value: "")  // Could be clearer

    // Boolean without prefix
    let processing = BehaviorRelay<Bool>(value: false)  // → isProcessing
    let valid = BehaviorRelay<Bool>(value: false)       // → hasValidAmount

    // Generic names
    let result = BehaviorRelay<PaymentResult?>(value: nil)  // → paymentResult
    let error = BehaviorRelay<String?>(value: nil)          // → errorMessage

    // Abbreviated initializer
    init(uc: PaymentUseCase, val: ValidationService) {      // Bad parameter names
        self.pmtUC = uc
        self.valService = val
        super.init()
    }

    // Vague method names
    func process() { }                           // → processPaymentRequest()
    func validate() -> Bool { }                  // → validatePaymentAmount()
    func clear() { }                             // → clearPaymentForm()
    func handle(_ r: PaymentResult) { }          // → handlePaymentSuccess()
}

Refactoring Examples

Example: Refactoring Poor Names

Before (Bad)

class TrxVM: BaseViewModel<TrxState> {
    let trxs = BehaviorRelay<[Trx]>(value: [])
    let loading = BehaviorRelay<Bool>(value: false)

    func getTrx(id: String) -> Trx? {
        return trxs.value.first { $0.id == id }
    }

    func proc() {
        loading.accept(true)
        // Process transactions
    }
}

After (Good)

class TransactionViewModel: BaseViewModel<TransactionState> {
    let transactions = BehaviorRelay<[Transaction]>(value: [])
    let isLoading = BehaviorRelay<Bool>(value: false)

    func getTransaction(by id: String) -> Transaction? {
        return transactions.value.first { $0.id == id }
    }

    func processTransactions() {
        isLoading.accept(true)
        // Process transactions
    }
}

Changes Made:

  1. TrxVMTransactionViewModel (full names, proper suffix)
  2. trxstransactions (no abbreviation, plural)
  3. loadingisLoading (boolean prefix)
  4. getTrxgetTransaction (full name, clear parameters)
  5. procprocessTransactions (verb-based, descriptive)

Quick Reference Checklist

Use this when reviewing naming:

## Naming Conventions Checklist

### Classes/Structs/Enums
- [ ] PascalCase
- [ ] Descriptive and meaningful
- [ ] Proper suffix (ViewModel, UseCase, etc.)
- [ ] No abbreviations

### Variables/Properties
- [ ] camelCase
- [ ] Meaningful names
- [ ] Booleans have is/has/should/can prefix
- [ ] Collections are plural
- [ ] No single letters (except loops)
- [ ] No abbreviations

### Functions/Methods
- [ ] camelCase
- [ ] Verb-based (actions) or get/has/is (queries)
- [ ] Descriptive of purpose
- [ ] Clear parameter names

### IBOutlets
- [ ] Include type suffix
- [ ] Descriptive of purpose
- [ ] camelCase

### General
- [ ] No generic names (Manager, Helper, Util)
- [ ] Consistent naming style
- [ ] Easy to understand without context