| name | swift |
| description | Google's official Swift style guide. Covers naming conventions, optionals, protocols, error handling, access control, formatting, and Swift best practices. |
Google Swift Style Guide
Official Google Swift coding standards for consistent, maintainable iOS/macOS code.
Golden Rules
- Clear, descriptive names — readability at the call site
- Prefer
let over var — immutability by default
- Use optionals properly — avoid force unwrapping (
!)
- Protocol-oriented programming — prefer protocols over inheritance
guard for early returns — reduce nesting with early exits
- Use type inference — let Swift infer types when obvious
- SwiftLint for consistency — automate style enforcement
Quick Reference
Naming Conventions
| Element | Convention | Example |
|---|
| Types (class/struct/enum/protocol) | UpperCamelCase | UserService |
| Functions/Methods | lowerCamelCase | getUserById |
| Variables/Properties | lowerCamelCase | userCount |
| Constants | lowerCamelCase | maxRetries |
| Enums | UpperCamelCase | Direction |
| Enum cases | lowerCamelCase | .up, .down, .left |
| Type aliases | UpperCamelCase | CompletionHandler |
Variables and Constants
let userName = "Alice"
let maxRetries = 3
var retryCount = 0
retryCount += 1
let users: [User] = []
let count = users.count
Optionals
if let user = getUser(id: 42) {
print(user.name)
}
func processUser(id: Int) {
guard let user = getUser(id: id) else {
print("User not found")
return
}
display(user)
}
let name = user?.name ?? "Unknown"
let user = getUser(id: 42)!
Structs and Classes
struct User {
let id: Int
var name: String
var email: String
}
final class UserService {
private let repository: UserRepository
init(repository: UserRepository) {
self.repository = repository
}
func getUser(id: Int) async throws -> User {
return try await repository.find(id: id)
}
}
Protocols
protocol UserRepository {
func find(id: Int) async throws -> User
func save(_ user: User) async throws
}
extension UserRepository {
func findAll() async throws -> [User] {
return []
}
}
typealias UserStore = UserRepository & Codable
Error Handling
enum UserError: Error {
case notFound(id: Int)
case invalidData(String)
case networkFailure(underlying: Error)
}
func fetchUser(id: Int) throws -> User {
guard let user = database[id] else {
throw UserError.notFound(id: id)
}
return user
}
do {
let user = try fetchUser(id: 42)
display(user)
} catch UserError.notFound(let id) {
print("User \(id) not found")
} catch {
print("Unexpected error: \(error)")
}
Async/Await
func loadUsers() async throws -> [User] {
let data = try await networkClient.get("/api/users")
return try JSONDecoder().decode([User].self, from: data)
}
Task {
do {
let users = try await loadUsers()
await MainActor.run { self.users = users }
} catch {
await MainActor.run { self.error = error }
}
}
Access Control
public struct User {
public let id: Int
public var name: String
internal var metadata: [String: String]
private var _internalState: Bool
}
public final class AuthService {
}
Formatting
users.forEach { user in
print(user.name)
}
let activeUsers = users.filter { $0.isActive }
let names = users.map { $0.name }
func process() {
if condition {
doSomething()
}
}
Common Mistakes
| Mistake | Correct Approach |
|---|
Force unwrapping (!) | Use if let, guard let, or nil coalescing |
var everywhere | Use let by default; var only when mutating |
| Class for everything | Prefer struct for value semantics |
| No error handling | Use throws / do-catch |
| Inheritance over protocols | Favor protocol composition |
| No access control | Explicitly mark public, internal, private |
| Implicit self in closures | Use [weak self] to avoid retain cycles |
When to Use This Guide
- Writing new Swift code
- Refactoring existing Swift
- Code reviews
- Setting up SwiftLint rules
- Onboarding new team members
Install
npx skills add testdino-hq/google-styleguides-skills/swift
Full Guide
See swift.md for complete details, examples, and edge cases.