Skip to main content

πŸ’¬πŸ“ File and Components Naming

The focus of this document is to provide clear and actionable rules for naming within Swift and SwiftUI projects, while excluding folder organization and architecture-specific patterns such as MVVM or VIPER. For these aspects, refer to complementary documentation on project organization and architecture guidelines.

General Naming Guidelines​

Consistency and Clarity​

Consistency and clarity are the cornerstones of effective naming conventions. Names should clearly convey the purpose and functionality of the element they represent. Consistent naming patterns across the codebase make it easier to understand and maintain, especially as the project scales.

  • Use Descriptive Names: Choose names that accurately describe the role of the variable, function, or type. Avoid single-letter names or overly short names except for loop indices or very common abbreviations (e.g., i, x, y).
  • Avoid Ambiguity: Names should be specific enough to avoid confusion. For example, use userProfile instead of profile if the context involves multiple types of profiles.

Use of Descriptive Names​

Descriptive names help developers quickly understand what a piece of code does. This is particularly important in collaborative environments where multiple developers work on the same codebase.

  • Methods and Functions: Use action-oriented names for functions and methods, starting with a verb that describes what the function does (e.g., fetchUserData(), updateProfile()).
  • Classes and Structs: Use nouns that represent the entity or concept the type models (e.g., UserManager, Order).
  • Variables: Choose variable names that represent the data they hold. For example, use userName instead of just name to specify that it’s a user’s name.

Capitalization Rules​

Adhere to Swift’s capitalization rules to maintain a consistent style across your codebase.

  • PascalCase for Types and File Names: Use PascalCase (e.g., UserProfileView, LoginManager) for classes, structs, enums, protocols, and file names. Each word in the name should start with a capital letter.
  • camelCase for Variables and Functions: Use camelCase (e.g., userName, fetchUserData()) for variable names, properties, methods, and functions. The first word should be in lowercase, and each subsequent word should start with a capital letter.
  • SCREAMING_SNAKE_CASE for Global Constants: Use SCREAMING_SNAKE_CASE (e.g., MAX_LOGIN_ATTEMPTS) for global constants and static values within enums.

Avoid Redundancy​

Avoid including redundant or unnecessary information in names, as it can make code harder to read and maintain.

  • Avoid Repeating Information: Don’t repeat the type in the name. For example, userArray is redundant if the type is [User]. Instead, use users.
  • Avoid Generic Names: Generic names like manager, data, or info provide little context. Be specific, like authManager or userData.
  • Avoid Long Names: Keep names concise yet descriptive. While it’s important to be specific, excessively long names can be cumbersome. Use 2-3 words that convey the component’s role.

Abbreviations and Acronyms​

Use abbreviations and acronyms sparingly and only when they are widely understood.

  • Common Abbreviations: Use common abbreviations like URL, ID, or JSON where appropriate. Avoid using non-standard abbreviations, as they can confuse other developers.
  • Avoid Shortened Words: Avoid creating your own abbreviations for commonly understood words (e.g., use button, not btn).

Prefixes and Suffixes​

Use prefixes and suffixes to add context to names, but only when necessary.

  • Boolean Variables: Use prefixes like is, has, or can for Boolean properties to indicate their purpose (e.g., isLoggedIn, hasAccess, canSubmit).
  • Delegates and Data Sources: Add Delegate or DataSource suffixes to indicate the role of the object (e.g., tableViewDelegate, collectionViewDataSource).
  • Protocols: Avoid using I prefixes (common in other languages like C#). Instead, use descriptive names that reflect the protocol’s role (e.g., Configurable, Validatable).

Use of Contextual Names​

Names should provide enough context to understand their use without being verbose.

  • Single Responsibility Names: Each name should reflect a single purpose or responsibility. For example, userManager is responsible for user-related actions, while authService handles authentication.
  • Include Context in Nested Scopes: When variables are used within closures or nested scopes, include context in the name to avoid ambiguity (e.g., currentUser instead of user in a nested loop or closure).

Temporary Variables​

Temporary variables should be used sparingly and named appropriately.

  • Loop Variables: Use single-letter names like i, j, k for loop indices, but provide descriptive names in more complex loops (e.g., userIndex).
  • Short-Lived Variables: For short-lived variables in small scopes, use concise names that indicate their role (e.g., tempData for temporary data storage).

Files​

Proper file naming is crucial for organizing code and ensuring that developers can easily locate and understand the purpose of each file. Following consistent file naming conventions helps maintain a clean and navigable project structure.

  • Use PascalCase for File Names: All Swift file names should use PascalCase, where each word begins with an uppercase letter (e.g., UserProfileView.swift, LoginManager.swift).
  • Match File Name with Primary Type: The file name should match the name of the primary type it contains. If a file contains a class named UserProfileView, the file should be named UserProfileView.swift.
  • Avoid Special Characters and Spaces: Do not use special characters (e.g., @, #, &) or spaces in file names. Use only alphanumeric characters and avoid underscores (_) and hyphens (-) to ensure compatibility and consistency.
  • Be Descriptive but Concise: File names should be descriptive enough to convey the purpose of the file but not overly long. Aim for clarity while keeping names manageable.

Specific Types​

Different types of Swift constructs, such as classes, structs, protocols, and extensions, have specific naming patterns to follow.

Classes and Structs​

  • File Names Should Match the Type Name: The file name should exactly match the name of the class or struct it contains. For example:
    • User.swift for a User struct or class.
    • AuthManager.swift for an AuthManager class.
  • Avoid Redundant Suffixes: Do not add unnecessary suffixes like Class or Struct in the file name (e.g., use User.swift instead of UserClass.swift).

Protocols​

  • File Names Should Match the Protocol Name: The file name should match the protocol name exactly. For example:
    • Configurable.swift for a Configurable protocol.
    • DataSourceProvider.swift for a DataSourceProvider protocol.
  • Extensions to Protocols: Use a suffix to indicate the functionality of the extension, such as ProtocolName+Functionality.swift (e.g., Configurable+Defaults.swift for default implementations of the Configurable protocol).

Enums​

  • File Names Should Match the Enum Name: The file name should be the same as the enum name. For example:
    • UserRole.swift for a UserRole enum defining different user roles.
    • OrderStatus.swift for an OrderStatus enum representing various order states.

Extensions​

  • Use the Format TypeName+Functionality.swift: When creating extensions, name the file using the type name and a short description of the functionality provided by the extension. For example:
    • String+Validation.swift for validation-related extensions to the String type.
    • UIView+Animations.swift for custom animation methods added to UIView.
  • Avoid Overloading Extension Files: Keep related extensions grouped together, but avoid overloading a single file with too many unrelated extensions. Split extensions into multiple files if necessary, using descriptive names.

Multi-Type Files​

  • Use Descriptive Names for Multi-Type Files: If a file contains multiple related types (e.g., models or utility functions), choose a name that reflects its contents. For example:
    • UserProfileModels.swift for a file containing multiple models related to user profiles.
    • NetworkHelpers.swift for a file containing utility functions related to networking.

Utility Files​

Utility files often contain helper functions, constants, or other shared resources. Use clear and specific names to indicate their purpose.

Helpers and Utilities​

  • Use Descriptive Names Reflecting the Utility’s Purpose: File names should describe the function or role of the utilities within. For example:
    • NetworkHelper.swift for networking-related utility functions.
    • DateFormatterUtility.swift for utilities related to date formatting.

Constants and Configurations​

  • Use Specific Names for Constants Files: Use names that indicate the scope of the constants, such as AppConstants.swift for application-wide constants or APIConstants.swift for constants related to API configurations.
  • Avoid Overloading Constants Files: Avoid creating a single, large constants file for all constants. Instead, split constants into logical groups based on their use.

Extensions and Categories​

  • Use TypeName+Functionality.swift for Extensions: As mentioned above, categorize extension files based on the type and the specific functionality being added. This approach makes it easier to find and manage extensions.
  • Keep Extensions Focused: Each extension file should focus on a specific area of functionality (e.g., UIView+Layout.swift for layout-related methods).

iOS-Specific Components​

iOS projects often include specific types of files that require unique naming conventions.

View Controllers​

  • Use the ViewController Suffix: All view controllers should have a name that reflects their purpose followed by ViewController. For example:
    • LoginViewController.swift for a login screen.
    • UserProfileViewController.swift for a user profile screen.
  • Navigation and Tab Controllers: For custom navigation or tab bar controllers, use names like CustomNavigationController.swift or MainTabBarController.swift.

Storyboard and XIB Files​

  • Match the File Name to the Corresponding View Controller or Component: Storyboard and XIB file names should match the name of the corresponding view controller or UI component (e.g., LoginViewController.storyboard, UserProfileCell.xib).
  • Use Descriptive Names for Reusable Components: For reusable UI components, use names that reflect their role (e.g., CustomButton.xib, UserProfileHeaderView.xib).

Types​

Classes and Structs​

Classes and structs are fundamental building blocks in Swift. Proper naming helps distinguish their purpose and makes the code more intuitive.

  • Use PascalCase: Use PascalCase for all class and struct names, capitalizing the first letter of each word (e.g., UserProfile, LoginManager).
  • Use Nouns: Name classes and structs using nouns that describe the object or entity they represent (e.g., Order, ProductCatalog). Avoid using verbs or adjectives.
  • Avoid Redundant Suffixes: Do not include unnecessary suffixes like Class or Struct in the name. For example, use User instead of UserClass or UserStruct.
  • Indicate Responsibility Clearly: Choose names that clearly convey the class or struct’s role in the codebase (e.g., AuthenticationService for handling authentication, UserSettings for user-specific preferences).
NamePurposeExample
UserProfileRepresents an individual user's profile.class UserProfile {}
OrderManagerManages operations related to orders.struct OrderManager {}
AuthServiceHandles authentication logic.class AuthService {}
ProductCatalogRepresents a collection of products.struct ProductCatalog {}

Protocols​

Protocols define a blueprint of methods and properties for conforming types. They should be named to reflect their purpose clearly.

  • Use PascalCase: Use PascalCase for all protocol names, with the first letter of each word capitalized (e.g., Configurable, DataSourceProvider).
  • Use Descriptive Adjectives or Nouns: Use adjectives (e.g., Configurable, Validatable) or nouns (e.g., DataSource, Delegate) that describe the protocol’s purpose.
  • Avoid Using the "I" Prefix: Unlike languages like C# where interfaces use the I prefix, Swift protocols should not use this convention (e.g., UserProtocol is incorrect; use UserDelegate instead).
NamePurposeExample
ConfigurableRepresents something that can be configured.protocol Configurable {}
DataSourceProviderProvides data to a UI component.protocol DataSourceProvider {}
ValidatableRepresents an object that can be validated.protocol Validatable {}
NetworkingDefines networking operations for an object.protocol Networking {}

Enums​

Enums are used to define a common type for a group of related values. Naming should be intuitive and reflect the purpose of the values.

  • Use PascalCase: Use PascalCase for the enum name and for its cases (e.g., OrderStatus, UserRole).
  • Use Singular Nouns: The enum name should typically be a singular noun that represents the group of values (e.g., PaymentMethod).
  • Use Verb Phrases for Actions: If the enum represents actions or state transitions, use verb phrases (e.g., LoadingState with cases like loading, success, failure).
  • Avoid Adding "Enum" Suffix: Do not add "Enum" to the name; it is redundant (e.g., UserRoleEnum is incorrect; use UserRole).
NamePurposeExample
OrderStatusRepresents the status of an order.enum OrderStatus { case pending, shipped, delivered }
UserRoleDefines the roles a user can have within the application.enum UserRole { case admin, user, guest }
PaymentMethodLists different payment methods available.enum PaymentMethod { case creditCard, paypal, applePay }
LoadingStateRepresents the state of a loading process.enum LoadingState { case loading, success, failure }

Extensions​

Extensions allow you to add functionality to existing types. Proper naming helps organize the additional functionality and clarifies its purpose.

  • Use the Format TypeName+Functionality: Use the format TypeName+Functionality to name extension files (e.g., String+Validation.swift).
  • Group Related Functions: Group related methods in a single extension to improve code organization (e.g., UIView+Layout for layout-related methods).
  • Avoid Adding Unrelated Functions: Do not add unrelated methods in the same extension, as it reduces clarity and organization.
NamePurposeExample
String+ValidationAdds validation-related methods to the String type.extension String { func isValidEmail() -> Bool {} }
UIView+AnimationsAdds custom animations to UIView.extension UIView { func shake() {} }
Date+FormattingAdds date formatting functions to Date.extension Date { func formatted() -> String {} }
Array+SafeAccessAdds safe access methods to arrays.extension Array { func safeElement(at index: Int) -> Element? {} }

Type Aliases and Associated Types​

Type aliases and associated types provide a way to create more readable code by giving a type a new name. They are often used in protocols and generics.

  • Use Descriptive Names: Choose names that clearly describe the role of the type alias or associated type (e.g., JSONDictionary for [String: Any]).
  • Avoid Generic Names: Avoid using generic names like T or Element unless in generic contexts where their role is obvious.
  • Use camelCase for Aliases within Methods: For method-local aliases, use camelCase to distinguish them from top-level type aliases.
NamePurposeExample
JSONDictionaryRepresents a dictionary used for JSON parsing.typealias JSONDictionary = [String: Any]
ElementRepresents an element in a generic context, such as a collection.associatedtype Element
CompletionHandlerA closure that is called when an operation completes.typealias CompletionHandler = (Result<Data, Error>) -> Void

Functions and Methods​

Functions and Methods​

Functions and methods should have clear, descriptive names that reflect their purpose and behavior. They are the actions in your code, so naming them appropriately is crucial for readability and maintainability.

  • Use Verb Phrases: Start function names with a verb to indicate the action being performed (e.g., fetchUserData(), updateProfile()).
  • Be Descriptive Yet Concise: Use names that are specific enough to convey the function’s purpose but not overly long. Avoid vague names like doSomething() or handle().
  • Include Context When Necessary: If a function is performing an action related to a specific entity or context, include that in the name (e.g., saveUserSettings() instead of just save()).
  • Avoid Redundant Words: Do not include redundant terms like function or method in the name (e.g., use getData() instead of getDataMethod()).
NamePurposeExample
fetchUserData()Retrieves user data from a remote server.func fetchUserData() {}
updateProfile(with:)Updates the user profile with the provided data.func updateProfile(with data: UserProfile) {}
saveSettings()Saves user settings locally or remotely.func saveSettings() {}
deleteAccount()Deletes the user’s account from the system.func deleteAccount() {}

Boolean Methods and Properties​

Boolean methods and properties should be named to clearly indicate a true/false condition. This convention helps in understanding the state or behavior of an object.

  • Use Prefixes Like is, has, or can: These prefixes clarify that the method or property returns a Boolean value.
    • is: Indicates a state (e.g., isLoggedIn).
    • has: Indicates possession or availability (e.g., hasAccess).
    • can: Indicates a capability (e.g., canSubmit).
  • Avoid Negatively Named Booleans: Instead of naming a property isNotLoggedIn, use !isLoggedIn in the code for clarity.
NamePurposeExample
isLoggedInIndicates whether the user is currently logged in.var isLoggedIn: Bool = false
hasPremiumAccessIndicates if the user has access to premium features.var hasPremiumAccess: Bool = true
canSubmitForm()Checks if the form meets all requirements for submission.func canSubmitForm() -> Bool {}
isFormValidReturns true if the form data is valid.var isFormValid: Bool = false

Delegate and Data Source Methods​

Delegate and data source methods should be named to reflect the events or actions they handle. They often use a pattern of describing the component, the event, and the response.

  • Use Descriptive Method Names: Include the name of the object that triggers the event, the action that occurs, and any relevant context (e.g., tableView(_:didSelectRowAt:)).
  • Follow the subjectVerbObject Pattern: This pattern helps in making delegate methods more readable (e.g., buttonDidTap(_:)).
  • Use Optional Parameters When Possible: For delegate methods that may not require all parameters in every implementation, consider using optional parameters to keep the method signature concise.
NamePurposeExample
tableView(_:didSelectRowAt:)Called when a user selects a row in a table view.func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
textFieldDidBeginEditing(_:)Notifies that a text field has started editing.func textFieldDidBeginEditing(_ textField: UITextField) {}
buttonDidTap(_:)Handles tap events on a custom button.func buttonDidTap(_ button: UIButton) {}
collectionView(_:cellForItemAt:)Provides the cell for a specific item in a collection view.func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {}

Closures and Callbacks​

Closures and callbacks are often used for asynchronous operations or event handling. Proper naming helps clarify their role and expected behavior.

  • Use completion or handler Suffix: Use completion or handler as a suffix to indicate that the closure is a callback (e.g., fetchDataCompletion).
  • Describe the Purpose of the Closure: If the closure has a specific role, include that in the name (e.g., loginCompletionHandler).
  • Use Descriptive Parameter Names: When defining closures, use descriptive names for the parameters to clarify what each value represents.
NamePurposeExample
completionHandlerIndicates a closure that will be called upon completion of an operation.func fetchData(completionHandler: @escaping (Result<Data, Error>) -> Void) {}
loginCompletionA closure called after a login attempt, passing a Boolean indicating success.func performLogin(completion: @escaping (Bool) -> Void) {}
fetchDataCompletionCalled after data is fetched, passing a result object.func fetchData(completion: @escaping (Result<User, Error>) -> Void) {}

Parameters​

Parameter names in functions and methods should be clear and descriptive, reflecting the purpose of the argument.

  • Use External and Internal Parameter Names: Use external parameter names to describe the role of the parameter in the function, and internal names to use within the function body (e.g., func updateProfile(for userID: String, with data: UserProfile)).
  • Avoid Using and in Parameter Names: Combining multiple responsibilities in one parameter name can be confusing. Use separate parameters instead of names like saveUserAndNotify.
  • Use Default Parameter Values: For optional behaviors, provide default values for parameters (e.g., func displayAlert(message: String, title: String = "Alert")).
NamePurposeExample
for userIDExternal parameter name for provides context, while userID is used internally.func updateProfile(for userID: String, with data: UserProfile) {}
with datawith indicates the relationship of the parameter data to the function.func saveProfile(with data: UserProfile) {}
message: String, title: String = "Alert"Sets a default value for the title parameter while requiring the message parameter.func displayAlert(message: String, title: String = "Alert") {}
completion: @escaping (Bool) -> VoidDescribes a completion handler that expects a Boolean result.func submitForm(completion: @escaping (Bool) -> Void) {}

Variables and Constants​

Variables and Properties​

Variables and properties should have descriptive names that clearly indicate their purpose and content. This makes the code more readable and maintainable.

  • Use camelCase: Use camelCase for all variable and property names, starting with a lowercase letter and capitalizing each subsequent word (e.g., userName, isLoggedIn).
  • Be Descriptive: Choose names that reflect the role or purpose of the variable. Avoid generic names like data or temp.
  • Use Context-Specific Names: If a variable is scoped within a function or a class, use names that provide context (e.g., currentUser instead of just user).
  • Avoid Redundant Prefixes: Avoid prefixes like m_ or self. for properties unless necessary to differentiate from method parameters.
NamePurposeExample
userFullNameStores the full name of the user.var userFullName: String = "John Doe"
isUserAuthenticatedIndicates whether the user has successfully logged in.var isUserAuthenticated: Bool = false
currentTemperatureRepresents the current temperature value in a weather app.var currentTemperature: Double = 72.5
remainingItemsNumber of items left in stock.var remainingItems: Int = 10
sessionTokenStores the user session token for authentication.var sessionToken: String?
shouldShowAlertControls whether an alert should be displayed.var shouldShowAlert: Bool = true
totalAmountRepresents the total amount in a shopping cart.var totalAmount: Decimal = 99.99
selectedCategoryHolds the selected category in a filter view.var selectedCategory: Category?

Instances of Classes and Structs​

Instances of classes and structs should have names that describe their role within the context of the application.

  • Use Descriptive Names: Choose names that reflect the instance's purpose or role, such as userManager for an instance of UserManager.
  • Avoid Generic Names: Avoid using generic names like manager or controller. Instead, specify the context (e.g., authManager, networkController).
  • Singleton Instances: Use shared or default as a prefix for singleton instances (e.g., sharedSession).
NamePurposeExample
userManagerManages user-related operations like login and profile updates.let userManager = UserManager()
authServiceHandles authentication processes, such as login and logout.let authService = AuthService()
databaseControllerManages interactions with the database.let databaseController = DatabaseController()
paymentGatewayFacilitates payment processing.let paymentGateway = PaymentGateway()
analyticsTrackerTracks user interactions and events for analytics purposes.let analyticsTracker = AnalyticsTracker()
fileDownloaderDownloads files from the internet.let fileDownloader = FileDownloader()
networkManagerHandles network requests and connectivity status.let networkManager = NetworkManager()
locationProviderProvides the current location of the user.let locationProvider = LocationProvider()

Collections of Instances​

Collections should have names that clearly indicate the type and purpose of the items they contain.

  • Use Plural Nouns: Use plural forms to indicate that the variable is a collection (e.g., users, products).
  • Include Context: Include context about what the collection represents (e.g., activeUsers instead of just users).
  • Avoid Suffixes Like List or Array: Do not use redundant suffixes like list or array in the name (e.g., use items instead of itemList).
NamePurposeExample
registeredUsersA collection of users who have registered in the app.var registeredUsers: [User]
downloadedFilesAn array of files downloaded by the user.var downloadedFiles: [File]
availableProductsList of products available for purchase.var availableProducts: [Product]
activeSessionsTracks active user sessions in the app.var activeSessions: [Session]
completedOrdersContains orders that have been processed and completed.var completedOrders: [Order]
favoriteArticlesCollection of articles marked as favorite by the user.var favoriteArticles: [Article]
pendingInvitationsList of invitations waiting for user action.var pendingInvitations: [Invitation]
recentSearchesStores recent search queries made by the user.var recentSearches: [String]

Constants​

Constants should have clear, descriptive names and use consistent formatting to indicate that their values do not change.

  • Use PascalCase for Global Constants: Use PascalCase for global constants and constants defined at the top level of a class or struct (e.g., MaxLoginAttempts).
  • Use SCREAMING_SNAKE_CASE for Enumerations: Use SCREAMING_SNAKE_CASE for constants defined within enums (e.g., API_BASE_URL).
  • Group Related Constants: Group related constants into structs or enums to keep them organized (e.g., struct API { static let baseURL = "https://api.example.com" }).
NamePurposeExample
MaxRetryAttemptsMaximum number of retry attempts for a network request.let MaxRetryAttempts = 3
DefaultUserAvatarURLDefault URL for a user's avatar image if none is provided.let DefaultUserAvatarURL = "https://example.com/default-avatar.png"
DefaultTimeoutIntervalDefault timeout for network requests in seconds.let DefaultTimeoutInterval: TimeInterval = 30.0
API.baseURLBase URL for the API endpoints.struct API { static let baseURL = "https://api.example.com" }
NotificationKeys.UserDidLoginNotification key for user login events.struct NotificationKeys { static let UserDidLogin = "UserDidLoginNotification" }
ErrorMessages.invalidEmailError message displayed for invalid email input.struct ErrorMessages { static let invalidEmail = "Please enter a valid email address." }
ThemeColors.primaryColorPrimary color used throughout the app's UI.struct ThemeColors { static let primaryColor = UIColor.blue }
AnimationDurations.defaultDefault duration for animations.struct AnimationDurations { static let default = 0.3 }

Enumerations for Constants​

NamePurposeExample
APIEndpoints.getUserDefines the endpoint for fetching user data.enum APIEndpoints { static let getUser = "/user" }
Theme.Fonts.titleDefines the font used for title labels.struct Theme { struct Fonts { static let title = UIFont.systemFont(ofSize: 18) } }
UserRoles.adminRepresents the admin role for a user in the app.enum UserRoles { case admin, user, guest }
ErrorCodes.networkErrorError code for network-related issues.enum ErrorCodes { static let networkError = 1001 }
UserDefaultsKeys.hasSeenIntroKey for tracking whether the user has seen the introduction screen.enum UserDefaultsKeys { static let hasSeenIntro = "HasSeenIntro" }

iOS-Specific Components​

View Controllers​

View controllers are a core component of UIKit, managing the views and coordinating interactions between the model and view layers. Proper naming helps clarify their role and purpose.

  • Use the ViewController Suffix: Always use the ViewController suffix for classes that inherit from UIViewController (e.g., LoginViewController, SettingsViewController).
  • Descriptive Prefixes: Use prefixes that describe the view controller’s purpose or the feature it manages (e.g., UserProfileViewController for managing user profile screens).
  • Navigation and Tab Controllers: For custom navigation or tab bar controllers, use names like CustomNavigationController or MainTabBarController to indicate their specialized role.
NamePurposeExample
LoginViewControllerManages user login interactions.class LoginViewController: UIViewController {}
UserProfileViewControllerDisplays and edits the user profile.class UserProfileViewController: UIViewController {}
SettingsViewControllerHandles app settings and preferences.class SettingsViewController: UIViewController {}
MainNavigationControllerCustom navigation controller for handling main app flow.class MainNavigationController: UINavigationController {}
CustomTabBarControllerManages the custom tab bar interface and interactions.class CustomTabBarController: UITabBarController {}

SwiftUI Components​

SwiftUI introduces a new paradigm for building user interfaces. Naming conventions for SwiftUI components should reflect their role and reusability.

  • Use Descriptive Names: Use names that reflect the component's role and content (e.g., UserProfileView, LoginButton).
  • Use the View Suffix: Add the View suffix for standard SwiftUI views to differentiate them from other types (e.g., SettingsView).
  • Reusable Components: Name reusable components with a clear purpose and context (e.g., PrimaryButton, CustomTextField).
NamePurposeExample
UserProfileViewDisplays detailed information about the user profile.struct UserProfileView: View {}
SettingsViewManages and displays app settings.struct SettingsView: View {}
LoginButtonCustom button used for login actions.struct LoginButton: View {}
CustomTextFieldCustomized text field with specific styling.struct CustomTextField: View {}
ContentViewMain entry point for the app’s user interface.struct ContentView: View {}

UIKit Components​

Custom UIKit components such as buttons, cells, and controls should have names that reflect their function and customization.

  • Use Descriptive Names: Name components based on their specific role (e.g., PrimaryButton for a main action button).
  • Include Context: Use names that provide context, such as UserProfileCell for a table view cell that displays user profiles.
  • Custom Views: For custom views, use names that describe the content and layout, like UserProfileHeaderView.
NamePurposeExample
PrimaryButtonCustom button styled for primary actions.class PrimaryButton: UIButton {}
SecondaryButtonCustom button for secondary actions.class SecondaryButton: UIButton {}
UserProfileCellCustom table view cell for displaying user profiles.class UserProfileCell: UITableViewCell {}
CustomSwitchCustom toggle switch with additional features.class CustomSwitch: UISwitch {}
RoundedImageViewImage view with rounded corners.class RoundedImageView: UIImageView {}

Combine Framework​

The Combine framework is used for handling asynchronous events. Naming conventions for publishers and subscribers should reflect their role and data flow.

  • Descriptive Names: Use descriptive names that indicate what data the publisher or subscriber deals with (e.g., userUpdatesPublisher).
  • Use Publisher and Subscriber Suffixes: Add suffixes like Publisher and Subscriber to indicate the type's role in data flow.
NamePurposeExample
userUpdatesPublisherPublishes updates to user data.var userUpdatesPublisher: AnyPublisher<User, Error>
dataSubscriberSubscribes to receive updates from a data publisher.var dataSubscriber: AnyCancellable
networkStatusPublisherPublishes changes in network connectivity status.var networkStatusPublisher: AnyPublisher<Bool, Never>
authStateSubscriberSubscribes to authentication state changes.var authStateSubscriber: AnyCancellable
searchResultsPublisherPublishes search results based on user queries.var searchResultsPublisher: AnyPublisher<[SearchResult], Never>

CoreData​

CoreData entities and attributes should have clear, descriptive names that reflect their role in the data model.

  • Entity Names: Use PascalCase for entity names that describe the model (e.g., User, Order).
  • Attribute Names: Use camelCase for attribute names that describe the data stored (e.g., firstName, orderDate).
  • Avoid Redundancy: Do not include the entity name in attribute names (e.g., use name instead of userName for a User entity).
NamePurposeExample
UserRepresents a user entity in the CoreData model.class User: NSManagedObject {}
OrderRepresents an order placed by a user.class Order: NSManagedObject {}
firstNameStores the first name of a user.@NSManaged public var firstName: String?
orderDateDate when the order was placed.@NSManaged public var orderDate: Date?
totalAmountTotal amount of an order.@NSManaged public var totalAmount: Double

Resources and Assets​

Image Assets​

Image assets are an integral part of any iOS application. Proper naming helps maintain consistency and makes it easier to find and update assets.

  • Use snake_case for Asset Names: Use lowercase letters with underscores to separate words (e.g., icon_user_profile, bg_home_screen).
  • Use Descriptive Prefixes: Prefix the asset name with its type or usage (e.g., icon_, bg_ for background images, btn_ for button images).
  • Include Size and State Modifiers: If the asset has different sizes or states, include them in the name (e.g., icon_user_profile@2x, btn_submit_disabled).
NamePurposeExample
icon_user_profileIcon representing a user's profile.icon_user_profile.png
bg_home_screenBackground image for the home screen.bg_home_screen.jpg
btn_submit_disabledImage for the disabled state of a submit button.btn_submit_disabled.png
icon_notificationIcon used for notifications.icon_notification.png
bg_login_screen@2xRetina version of the login screen background image.bg_login_screen@2x.png

Colors​

Color assets should have clear, descriptive names that indicate their usage or context. This makes it easy to update themes or adapt for different design systems.

  • Use Descriptive Names Reflecting Usage: Use names that reflect the purpose or context, such as primaryColor, backgroundColor, textColor.
  • Themed Colors: If your app supports themes (e.g., light and dark modes), use prefixes like lightModePrimary, darkModeAccent.
  • Avoid Generic Names: Avoid names like blueColor or redColor. Instead, use names like errorColor or successColor to reflect their use.
NamePurposeExample
primaryColorPrimary color used throughout the app for buttons and links.primaryColor
secondaryTextColorColor used for secondary text elements.secondaryTextColor
errorColorColor used for error messages and icons.errorColor
backgroundColorDefault background color for views and screens.backgroundColor
lightModePrimaryPrimary color used in light mode.lightModePrimary

Fonts and Styles​

Fonts and text styles should be named according to their usage in the app, making it easy to apply consistent typography across different screens.

  • Use the Font Family and Style: Include the font family and style in the name (e.g., Roboto-Bold, OpenSans-Italic).
  • Use Descriptive Names for Text Styles: For reusable text styles, use names that describe the role, like titleFont, bodyFont.
  • Avoid Ambiguous Names: Avoid using generic names like customFont. Be specific about the style and weight.
NamePurposeExample
titleFontFont used for titles and headings.static let titleFont = "Helvetica-Bold"
bodyFontFont used for main body text.static let bodyFont = "OpenSans-Regular"
buttonFontFont used for buttons.static let buttonFont = "Roboto-Bold"
captionFontFont used for small captions and notes.static let captionFont = "OpenSans-LightItalic"
subtitleFontFont used for subtitles and secondary headings.static let subtitleFont = "Helvetica-Italic"

Localized Strings and Plurals​

Localized strings should have meaningful keys that make it easy to identify their usage. Plurals should be handled using appropriate key naming conventions to ensure clarity.

  • Use camelCase for Keys: Use camelCase for string keys (e.g., loginButtonTitle, errorMessage).
  • Group Keys by Feature: Organize keys by feature or screen to make localization files easier to manage (e.g., login_username_placeholder).
  • Use Contextual Names for Plurals: Use names that reflect the context of the plural, like numberOfItems or daysRemaining.
NamePurposeExample
loginButtonTitleTitle for the login button."loginButtonTitle" = "Log In";
welcomeMessageMessage displayed on the welcome screen."welcomeMessage" = "Welcome to the App!";
errorMessageGeneral error message for user input errors."errorMessage" = "An error has occurred.";
numberOfItemsPlural string indicating the number of items."numberOfItems" = "%d items";
daysRemainingPlural string for the number of days remaining."daysRemaining" = "%d days remaining";

Sounds​

Sound assets should be named to clearly indicate their purpose and context of use, such as alerts or notifications.

  • Use Descriptive Names: Name sounds based on their function, such as notification_alert or button_click.
  • Organize by Category: Group related sounds by category, using a prefix like alert_, button_, background_.
  • Include File Format: Ensure the file format (e.g., .mp3, .wav) is appropriate for the platform and file type.
NamePurposeExample
notification_alertSound played for notifications.notification_alert.mp3
button_clickSound for button click feedback.button_click.wav
background_musicBackground music loop for the main menu.background_music.mp3
success_chimeSound played on successful completion of an action.success_chime.wav
error_buzzError sound played when an invalid action occurs.error_buzz.mp3

Asset Catalog Organization​

Organizing assets within the catalog ensures that they are easy to find and manage.

  • Use Asset Folders: Group related assets into folders within the asset catalog (e.g., Icons, Backgrounds, Buttons).
  • Use Asset Sets for Variants: Use asset sets to manage different resolutions and states (e.g., icon_user_profile with 1x, 2x, 3x variants).
  • Naming Convention Consistency: Maintain a consistent naming convention across all assets to avoid confusion.
NamePurposeExample
IconsFolder containing all application icons.icon_user_profile, icon_settings
BackgroundsFolder for background images.bg_login_screen, bg_home_screen
ButtonsFolder for button images, including active and disabled states.btn_submit_active, btn_submit_disabled
SoundsFolder for all sound assets.button_click.wav, alert_tone.mp3

Storyboard and XIB Elements​

Storyboard Identifiers​

Storyboard identifiers are used to reference view controllers and segues within a storyboard. Proper naming makes it easier to manage navigation and transitions between scenes.

  • Use Descriptive Identifiers: Use identifiers that clearly describe the purpose or role of the view controller or segue (e.g., LoginViewControllerID, showUserProfileSegue).
  • Match with View Controller Names: The storyboard identifier should generally match the name of the view controller class (e.g., UserProfileViewControllerID for a UserProfileViewController).
  • Use CamelCase: Use camelCase or PascalCase for storyboard identifiers, avoiding spaces or special characters.
NamePurposeExample
LoginViewControllerIDIdentifier for the login view controller.LoginViewControllerID
showUserProfileSegueSegue identifier for transitioning to the user profile view.showUserProfileSegue
SettingsViewControllerIDIdentifier for the settings view controller.SettingsViewControllerID
unwindToHomeSegueIdentifier for an unwind segue back to the home screen.unwindToHomeSegue
MainTabBarControllerIDIdentifier for the main tab bar controller.MainTabBarControllerID

XIB Files and Outlets​

XIB files and their elements, such as buttons and labels, should have names that reflect their role and usage within the interface.

XIB File​

  • Match with Contained Class: The XIB file name should match the name of the view or view controller class it is associated with (e.g., CustomButton.xib for a CustomButton class).
  • Use PascalCase: Use PascalCase for XIB file names, avoiding underscores or spaces.
NamePurposeExample
CustomButton.xibXIB file for a reusable custom button.CustomButton.xib
UserProfileHeaderView.xibXIB file for a custom header view in user profile.UserProfileHeaderView.xib
LoginFormView.xibXIB file for a custom login form.LoginFormView.xib
SettingsTableViewCell.xibXIB file for a custom settings table view cell.SettingsTableViewCell.xib
RoundedImageView.xibXIB file for a custom image view with rounded corners.RoundedImageView.xib

Outlet​

Outlets should be named to reflect the role and type of the UI element they reference. This makes it easy to understand their purpose in the code.

  • Use camelCase: Use camelCase for outlet names, starting with a lowercase letter and using capital letters to separate words.
  • Include Element Type: Include the type of the element in the name (e.g., submitButton for a button, titleLabel for a label).
  • Avoid Prefixes like lbl or btn: Do not use abbreviations like lbl or btn in outlet names. Instead, use full descriptive names.
NamePurposeExample
userProfileImageViewOutlet for a UIImageView displaying the user profile picture.@IBOutlet weak var userProfileImageView: UIImageView!
submitButtonOutlet for a UIButton used to submit a form.@IBOutlet weak var submitButton: UIButton!
titleLabelOutlet for a UILabel displaying the screen title.@IBOutlet weak var titleLabel: UILabel!
emailTextFieldOutlet for a UITextField used for email input.@IBOutlet weak var emailTextField: UITextField!
loginActivityIndicatorOutlet for a UIActivityIndicatorView showing login progress.@IBOutlet weak var loginActivityIndicator: UIActivityIndicatorView!

Action​

Actions triggered by user interactions should be named to indicate the type of event and the element that triggers it.

  • Use Verb Phrases: Start action names with a verb that describes the interaction (e.g., submitButtonTapped, textFieldEditingChanged).
  • Include Element Name: Include the name of the UI element in the action method (e.g., loginButtonTapped).
  • Use camelCase: Use camelCase for action names, starting with a lowercase letter.
NamePurposeExample
submitButtonTappedAction triggered when the submit button is tapped.@IBAction func submitButtonTapped(_ sender: UIButton) {}
loginButtonTappedAction triggered when the login button is pressed.@IBAction func loginButtonTapped(_ sender: UIButton) {}
textFieldEditingChangedAction called when the text field content changes.@IBAction func textFieldEditingChanged(_ sender: UITextField) {}
sliderValueChangedAction triggered when the slider value is adjusted.@IBAction func sliderValueChanged(_ sender: UISlider) {}
switchToggledAction triggered when the switch is toggled.@IBAction func switchToggled(_ sender: UISwitch) {}

Segue Identifiers​

Segue identifiers are used to manage transitions between view controllers. Proper naming makes it easy to identify and manage these transitions.

  • Use Verb Phrases: Use names that describe the transition, such as showDetailSegue or presentSettingsSegue.
  • Include Source and Destination: If necessary, include the source and destination view controllers in the name for clarity (e.g., mainToSettingsSegue).
  • Use camelCase: Use camelCase for segue identifiers, starting with a lowercase letter.
NamePurposeExample
showUserProfileSegueSegue to show the user profile view.showUserProfileSegue
presentSettingsSegueSegue to present the settings view modally.presentSettingsSegue
mainToDetailSegueSegue from the main view to the detail view.mainToDetailSegue
loginToHomeSegueSegue to navigate from login to the home screen.loginToHomeSegue
showOrderHistorySegueSegue to display the order history view.showOrderHistorySegue

Error Handling​

Error Types and Enums​

Error types and enums represent different error conditions in your app. Proper naming helps developers quickly understand the context and type of error being handled.

  • Use Descriptive Names Ending with Error: Name error types and enums with a descriptive name followed by Error to indicate that they represent an error type (e.g., NetworkError, DatabaseError).
  • Use PascalCase for Enum Cases: Use PascalCase for enum cases to maintain consistency with Swift naming conventions (e.g., invalidURL, noDataAvailable).
  • Group Related Errors in a Single Enum: Group errors that belong to the same domain or context in a single enum (e.g., AuthenticationError for all authentication-related errors).
enum NetworkError: Error {
case invalidURL
case noDataAvailable
case requestFailed
}

enum DatabaseError: Error {
case dataNotFound
case readFailure
case writeFailure
}

enum AuthenticationError: Error {
case invalidCredentials
case userNotFound
case accountLocked
}
NamePurposeExample
NetworkErrorRepresents errors related to network requests.enum NetworkError: Error {}
DatabaseErrorDefines errors that occur when accessing the database.enum DatabaseError: Error {}
AuthenticationErrorHandles errors related to user authentication.enum AuthenticationError: Error {}
invalidCredentialsIndicates that the provided user credentials are invalid.case invalidCredentials
dataNotFoundError case for missing data in the database.case dataNotFound

Error Constants and Messages​

Error constants and messages should be named to clearly indicate the type of error and provide meaningful information to the developer and user.

  • Use Descriptive Names: Error constants should have descriptive names that convey the issue, such as invalidEmailError or networkTimeoutError.
  • Group Related Messages: Organize related error messages in structs or enums to maintain a clean and structured codebase.
  • Use PascalCase for Constants: Use PascalCase for error constant names, avoiding underscores or abbreviations.
struct ErrorMessages {
static let invalidEmail = "The email address entered is invalid."
static let passwordTooShort = "The password must be at least 8 characters long."
static let networkTimeout = "The network request timed out. Please try again later."
}

struct ValidationError {
static let missingRequiredFields = "Please fill out all required fields."
static let passwordsDoNotMatch = "The passwords entered do not match."
}

struct NetworkErrorMessages {
static let noInternetConnection = "No internet connection available. Please check your connection and try again."
static let serverUnavailable = "The server is currently unavailable. Please try again later."
}
NamePurposeExample
invalidEmailErrorIndicates an error when the email format is invalid.static let invalidEmail = "The email address entered is invalid."
networkTimeoutErrorDescribes an error when a network request times out.static let networkTimeout = "The network request timed out. Please try again later."
missingRequiredFieldsError message for missing form fields.static let missingRequiredFields = "Please fill out all required fields."
passwordsDoNotMatchError message when password confirmation fails.static let passwordsDoNotMatch = "The passwords entered do not match."
noInternetConnectionError message for no internet connectivity.static let noInternetConnection = "No internet connection available. Please check your connection and try again."

Error Handling Methods​

Methods for error handling should have names that clearly indicate their purpose and the type of error they handle.

  • Use Verb Phrases: Start method names with verbs to describe the action being taken, such as handle, show, or log.
  • Include Error Context: Include the context of the error in the method name (e.g., handleNetworkError, logDatabaseError).
  • Use Specific Method Names: Avoid generic names like processError or displayError. Be specific about the type of error being handled.
func handleNetworkError(_ error: NetworkError) {
switch error {
case .invalidURL:
print("The URL provided is invalid.")
case .noDataAvailable:
print("No data is available for the requested resource.")
case .requestFailed:
print("The network request failed. Please try again.")
}
}

func showAuthenticationError(_ error: AuthenticationError) {
switch error {
case .invalidCredentials:
showAlert(with: "Invalid login credentials. Please try again.")
case .userNotFound:
showAlert(with: "No user found with the provided information.")
case .accountLocked:
showAlert(with: "Your account is locked. Please contact support.")
}
}

func logDatabaseError(_ error: DatabaseError) {
switch error {
case .dataNotFound:
print("Data not found in the database.")
case .readFailure:
print("Failed to read data from the database.")
case .writeFailure:
print("Failed to write data to the database.")
}
}
NamePurposeExample
handleNetworkErrorHandles errors related to network issues.func handleNetworkError(_ error: NetworkError) {}
showAuthenticationErrorDisplays errors related to authentication failures.func showAuthenticationError(_ error: AuthenticationError) {}
logDatabaseErrorLogs errors encountered when interacting with the database.func logDatabaseError(_ error: DatabaseError) {}
showAlert(with:)Displays an alert with a specific error message.func showAlert(with message: String) {}
logErrorToAnalytics(_:)Logs the error details to an analytics service.func logErrorToAnalytics(_ error: Error) {}

Tests​

Unit Test Classes and Methods​

Unit tests verify the functionality of individual components in isolation. Naming test classes and methods correctly helps in understanding the scope and purpose of each test.

Test Class Naming​

  • Use the Tests Suffix: Append Tests to the name of the class being tested (e.g., UserViewModelTests, LoginManagerTests).
  • Include the Class Name: The test class name should include the class or module it is testing (e.g., UserViewModelTests for the UserViewModel class).
  • Group by Feature or Module: If a single class has many test cases, consider grouping them by feature or module (e.g., LoginFeatureTests).
NamePurposeExample
UserViewModelTestsContains unit tests for the UserViewModel class.class UserViewModelTests: XCTestCase {}
LoginManagerTestsTests functionality of the LoginManager class.class LoginManagerTests: XCTestCase {}
NetworkServiceTestsTests for network-related methods in NetworkService.class NetworkServiceTests: XCTestCase {}
SettingsViewModelTestsTests for user settings management in SettingsViewModel.class SettingsViewModelTests: XCTestCase {}
OrderHistoryFeatureTestsGroup of tests related to order history functionality.class OrderHistoryFeatureTests: XCTestCase {}

Test Method Naming​

  • Use test Prefix: Start each test method name with test to indicate that it is a test case (e.g., testUserLogin, testFetchUserData).
  • Describe the Expected Outcome: Include the specific condition or outcome being tested (e.g., testLoginSuccess, testFetchUserDataFailure).
  • Use camelCase: Use camelCase for method names, starting with lowercase and capitalizing each subsequent word.
NamePurposeExample
testUserLoginTests the user login functionality.func testUserLogin() {}
testFetchUserDataSuccessVerifies that user data is fetched successfully.func testFetchUserDataSuccess() {}
testInvalidCredentialsErrorChecks for an error when invalid login credentials are provided.func testInvalidCredentialsError() {}
testSettingsSaveFailureTests failure case for saving user settings.func testSettingsSaveFailure() {}
testOrderHistoryDisplayVerifies correct display of order history information.func testOrderHistoryDisplay() {}

UI Tests​

UI tests validate the user interface and user interactions within the app. Proper naming helps identify what part of the UI is being tested and the expected behavior.

UI Test Class Naming​

  • Use the UITests Suffix: Append UITests to the name of the view or feature being tested (e.g., LoginUITests, HomeScreenUITests).
  • Describe the View or Feature: Include the view or feature name in the class name (e.g., UserProfileUITests for testing the user profile screen).
  • Group by Feature or Screen: Group tests that interact with the same screen or feature (e.g., SettingsScreenUITests).
NamePurposeExample
LoginUITestsContains UI tests for the login screen.class LoginUITests: XCTestCase {}
UserProfileUITestsUI tests for the user profile view.class UserProfileUITests: XCTestCase {}
HomeScreenUITestsTests the main home screen UI and interactions.class HomeScreenUITests: XCTestCase {}
SettingsScreenUITestsUI tests for the settings screen.class SettingsScreenUITests: XCTestCase {}
OrderHistoryUITestsVerifies the UI for displaying order history.class OrderHistoryUITests: XCTestCase {}

UI Test Method Naming​

  • Use test Prefix: Begin each method name with test followed by the action or state being tested (e.g., testLoginButtonTap, testProfileUpdate).
  • Describe the UI Interaction: Include the specific user action or UI component being tested (e.g., testLoginButtonTap or testProfileImageChange).
  • Use camelCase: Use camelCase for method names, starting with lowercase and capitalizing each subsequent word.
NamePurposeExample
testLoginButtonTapTests that tapping the login button triggers the login process.func testLoginButtonTap() {}
testProfileImageChangeVerifies that changing the profile image works correctly.func testProfileImageChange() {}
testSettingsToggleSwitchTests that the settings toggle switch updates preferences correctly.func testSettingsToggleSwitch() {}
testOrderHistoryScrollChecks that the order history list scrolls smoothly.func testOrderHistoryScroll() {}
testSearchFunctionalityTests the search functionality in the home screen.func testSearchFunctionality() {}

Test Data and Mocks​

Test data and mock objects are often used in tests to simulate real-world scenarios. Proper naming helps differentiate them from real objects and clarifies their purpose.

Test Data Naming​

  • Use Mock or Test Prefix: Prefix test data or mock objects with Mock or Test to indicate their role (e.g., MockUser, TestOrder).
  • Describe the Data Type: Include the type of data in the name, such as User, Order, or Response (e.g., MockUser, TestLoginResponse).
  • Use Specific Names for Scenarios: Use specific names for data objects that represent particular test scenarios (e.g., MockUserInvalidEmail, TestOrderWithoutItems).
NamePurposeExample
MockUserRepresents a generic mock user object for testing.let mockUser = User(id: 1, name: "John Doe")
TestLoginResponseSimulates a login response from the server.let testLoginResponse = LoginResponse(success: true)
MockUserInvalidEmailRepresents a user object with an invalid email for testing error handling.let mockUserInvalidEmail = User(email: "invalid-email")
TestOrderWithoutItemsTest order object without items to test validation.let testOrderWithoutItems = Order(items: [])
MockNetworkServiceMock object for simulating network requests.let mockNetworkService = MockNetworkService()

Mock Object Naming​

  • Use Mock Prefix: Use the Mock prefix for mock classes or structs that simulate the behavior of real objects (e.g., MockAPIClient, MockUserService).
  • Include the Original Object’s Name: The mock class name should include the name of the real object it is simulating (e.g., MockUserManager for the UserManager class).
  • Use Descriptive Method Names: Mock methods should have names that clearly indicate the simulated behavior (e.g., simulateNetworkError()).
NamePurposeExample
MockAPIClientSimulates the behavior of a real API client.class MockAPIClient: APIClient {}
MockUserServiceMocks the user service for testing user-related functionality.class MockUserService: UserService {}
MockDatabaseManagerSimulates database operations for testing.class MockDatabaseManager: DatabaseManager {}
MockAuthManagerMocks the authentication manager to simulate login/logout scenarios.class MockAuthManager: AuthManager {}
MockOrderServiceMocks order service operations such as placing and canceling orders.class MockOrderService: OrderService {}

Swift Packages and Modules​

Swift Package Names​

Swift packages are reusable libraries or frameworks that can be imported into various projects. Proper naming helps developers identify the purpose and scope of the package.

  • Use PascalCase: Use PascalCase for package names, capitalizing the first letter of each word (e.g., NetworkingKit, UserAuthentication).
  • Be Descriptive Yet Concise: Choose names that clearly describe the package's functionality without being overly verbose (e.g., ImageProcessing, not ImageProcessingAndFiltering).
  • Avoid Generic Names: Avoid overly generic names like Utilities or Helpers. Instead, use names that reflect the package's specific purpose (e.g., DateUtilities).
NamePurposeExample
NetworkingKitProvides networking utilities and API client implementations.import NetworkingKit
UserAuthenticationHandles user login, registration, and authentication processes.import UserAuthentication
ImageProcessingOffers image manipulation and filtering functionalities.import ImageProcessing
CoreDataHelperSimplifies CoreData operations like saving and fetching data.import CoreDataHelper
PushNotificationManagerManages push notifications and permissions.import PushNotificationManager

Module Names​

Modules represent the scope of a package, encapsulating its types and functionalities. Proper naming ensures that modules are easy to understand and use.

  • Match the Package Name: The module name should generally match the package name to avoid confusion (e.g., NetworkingKit for a package named NetworkingKit).
  • Use Descriptive Names for Submodules: If the package is divided into submodules, use names that clearly describe their functionality (e.g., NetworkingKit.Authentication).
NamePurposeExample
NetworkingKitCore module of the NetworkingKit package.import NetworkingKit
NetworkingKit.AuthenticationSubmodule for handling authentication-related networking operations.import NetworkingKit.Authentication
ImageProcessing.FiltersSubmodule for applying filters to images.import ImageProcessing.Filters
CoreDataHelper.UtilitiesSubmodule for utility functions related to CoreData.import CoreDataHelper.Utilities
UserAuthentication.OAuthSubmodule for handling OAuth authentication.import UserAuthentication.OAuth

Components within Packages​

Within a Swift package, various components like classes, structs, enums, and protocols need clear and consistent naming to facilitate use and collaboration.

Classes and Structs​

  • Use PascalCase: Use PascalCase for class and struct names, similar to how you would name them in a regular Swift file (e.g., APIClient, UserManager).
  • Include the Module Prefix: If a class or struct is tightly coupled with its module, consider including the module prefix in the name (e.g., NetworkingAPIClient).
NamePurposeExample
APIClientRepresents a generic API client for making network requests.class APIClient {}
UserManagerManages user-related operations like login and registration.struct UserManager {}
ImageFilterApplies filters to images in the ImageProcessing package.struct ImageFilter {}
OAuthHandlerManages OAuth authentication flows in UserAuthentication.class OAuthHandler {}
PushNotificationServiceHandles push notification setup and delivery.class PushNotificationService {}

Protocols​

  • Use Adjective or Noun Descriptions: Protocols should be named to describe a capability or role (e.g., Configurable, Authenticatable).
  • Avoid Prefixes like I: Unlike some other languages, Swift protocols should not use the I prefix (e.g., IConfigurable is incorrect; use Configurable).
NamePurposeExample
ConfigurableProtocol for objects that can be configured.protocol Configurable {}
AuthenticatableProtocol for types that support authentication operations.protocol Authenticatable {}
NetworkRequestableProtocol defining methods for making network requests.protocol NetworkRequestable {}
ImageFilterableProtocol for applying filters to images.protocol ImageFilterable {}
PersistableProtocol for objects that can be saved to persistent storage.protocol Persistable {}

Enums​

  • Use PascalCase for Enum Names and camelCase for Cases: Use PascalCase for the enum name and camelCase for its cases (e.g., NetworkError, networkTimeout).
  • Group Related Constants: Use enums to group related constants or states, especially in complex modules.
NamePurposeExample
NetworkErrorDefines different types of network errors.enum NetworkError { case networkTimeout }
AuthenticationStateRepresents different states of user authentication.enum AuthenticationState { case loggedIn, loggedOut }
ImageFilterTypeSpecifies different types of image filters.enum ImageFilterType { case sepia, monochrome }
DatabaseOperationEnumerates various database operations like read and write.enum DatabaseOperation { case read, write }
PushNotificationTypeDefines different types of push notifications.enum PushNotificationType { case alert, badge, sound }

Resource and Asset in Packages​

Resources and assets like images, colors, and localizations should be named to reflect their purpose and usage within the package.

Images and Icons​

  • Use Descriptive Names with Context: Include the purpose or context in the name (e.g., icon_add, background_login).
  • Use snake_case: Use lowercase letters and underscores to separate words (e.g., icon_user_profile).
NamePurposeExample
icon_addIcon for the "Add" action.icon_add.png
background_loginBackground image for the login screen.background_login.jpg
button_primaryImage for the primary button state.button_primary.png
icon_notificationIcon used for notifications.icon_notification.png
bg_home_screenBackground image for the home screen.bg_home_screen.jpg

Colors​

  • Use Contextual Names: Name colors based on their usage (e.g., primaryColor, errorColor).
  • Support for Themes: Include theme prefixes if the package supports multiple themes (e.g., lightModePrimary).
NamePurposeExample
primaryColorPrimary color used throughout the app.primaryColor
secondaryTextColorColor used for secondary text elements.secondaryTextColor
errorColorColor used for error messages and icons.errorColor
backgroundColorDefault background color for views and screens.backgroundColor
lightModePrimaryPrimary color used in light mode.lightModePrimary

Build Configurations and Schemes​

Build Configurations​

Build configurations define how your app is built and deployed. Proper naming ensures that configurations are easily identifiable and manageable across different environments.

  • Use Environment and Purpose in the Name: Include both the environment (e.g., Debug, Release, Staging) and the purpose of the build (e.g., DebugTesting, ReleaseProduction).
  • Follow a Consistent Format: Use a consistent naming pattern like EnvironmentPurpose (e.g., DebugTesting, ReleaseProduction).
  • Use PascalCase: Use PascalCase for build configuration names to maintain clarity and consistency.
NamePurposeExample
DebugTestingUsed for debugging and testing features during development.DebugTesting
ReleaseProductionProduction build for release to the App Store.ReleaseProduction
StagingInternalBuild configuration for internal testing on a staging environment.StagingInternal
DebugLocalBuild configuration for local development and testing.DebugLocal
ReleaseBetaRelease configuration for beta testing with external users.ReleaseBeta

Schemes​

Schemes define the build configuration, target, and settings for running, testing, and profiling your app. Proper naming helps in distinguishing between different purposes, such as testing, deployment, and debugging.

  • Include the Target and Configuration: Use the target name followed by the build configuration to clarify the scheme’s purpose (e.g., AppName-ReleaseProduction).
  • Use PascalCase with Hyphen: Use PascalCase for names and separate the target and configuration with a hyphen (e.g., AppName-ReleaseBeta).
  • Describe the Environment or Role: Include a description of the environment or the scheme's role, such as AppName-Testing or AppName-Deployment.
NamePurposeExample
MyApp-ReleaseProductionScheme for releasing the production build of MyApp.MyApp-ReleaseProduction
MyApp-DebugTestingScheme for debugging and testing MyApp.MyApp-DebugTesting
MyApp-StagingInternalInternal staging scheme for testing MyApp.MyApp-StagingInternal
MyApp-ReleaseBetaScheme for beta testing MyApp with external users.MyApp-ReleaseBeta
MyApp-DebugLocalLocal development scheme for MyApp testing and debugging.MyApp-DebugLocal

Build Settings and Info.plist Keys​

Build settings and Info.plist keys control various aspects of your app’s configuration, such as versioning, bundle identifiers, and environment-specific settings.

Build Settings Naming​

  • Use Descriptive Names: Use names that clearly describe the setting’s purpose, such as BASE_URL, API_KEY, or ENABLE_LOGGING.
  • Use Uppercase with Underscores: Use uppercase letters with underscores to separate words for environment variables (e.g., API_BASE_URL, ENABLE_CRASH_REPORTING).
NamePurposeExample
API_BASE_URLBase URL for the API in the current environment.API_BASE_URL
ENABLE_LOGGINGEnables or disables logging based on the build configuration.ENABLE_LOGGING
APP_VERSIONRepresents the current version of the app.APP_VERSION
API_KEYAPI key used for authentication with the backend services.API_KEY
FEATURE_FLAG_NEW_UIToggles the new UI feature in the app.FEATURE_FLAG_NEW_UI

Info.plist Keys Naming​

  • Use CamelCase: Use camelCase for custom Info.plist keys to match Apple’s conventions (e.g., isFeatureEnabled).
  • Include Feature Context: Include the feature or purpose in the key name to make it clear what the key controls (e.g., enableFeatureX, isBetaVersion).
NamePurposeExample
isFeatureEnabledControls whether a specific feature is enabled in the app.isFeatureEnabled
enableBetaFeaturesToggles access to beta features in the app.enableBetaFeatures
apiBaseURLDefines the base URL for API requests.apiBaseURL
supportEmailAddressSpecifies the support email address for user queries.supportEmailAddress
isBetaVersionIndicates whether the app is a beta version.isBetaVersion

Configuration Files​

Configuration files, such as .xcconfig files, store build settings and environment-specific configurations. Proper naming makes these files easier to manage and identify.

  • Use the Configuration and Environment: Name configuration files based on the build configuration and environment (e.g., Debug.xcconfig, ReleaseProduction.xcconfig).
  • Include the Target Name: If the configuration file is specific to a target, include the target name in the file name (e.g., AppName-Debug.xcconfig).
  • Use Descriptive File Names: Use names that reflect the file’s role, such as EnvironmentVariables.xcconfig or FeatureFlags.xcconfig.
NamePurposeExample
Debug.xcconfigConfiguration file for the debug build.Debug.xcconfig
ReleaseProduction.xcconfigConfiguration file for the release production build.ReleaseProduction.xcconfig
AppName-Debug.xcconfigDebug configuration file specific to the AppName target.AppName-Debug.xcconfig
EnvironmentVariables.xcconfigStores environment-specific variables like API keys and URLs.EnvironmentVariables.xcconfig
FeatureFlags.xcconfigConfiguration file for managing feature flags in different environments.FeatureFlags.xcconfig

Scheme Actions Naming​

Scheme actions define the pre- and post-build scripts, environment variables, and settings for running and testing your app. Proper naming helps keep these actions organized.

  • Use Verb Phrases: Use verb phrases to describe the action being performed (e.g., RunTests, UploadBuild, GenerateMocks).
  • Include Context: Include the context or target of the action, such as RunUnitTests or BuildDocumentation.
  • Use PascalCase: Use PascalCase for naming actions to keep the naming consistent and clear.
NamePurposeExample
RunUnitTestsAction to run unit tests before the build.RunUnitTests
UploadBuildAction to upload the build to the distribution platform.UploadBuild
GenerateMocksAction to generate mock files for testing.GenerateMocks
BuildDocumentationAction to build project documentation using a specified tool.BuildDocumentation
DeployToStagingAction to deploy the current build to the staging environment.DeployToStaging