npx agentspec-cli install 02bd73ed-de62-424e-a44a-5ff1dad1a89f --file-type cursor-rules→ .cursor/rules/
---
description:
globs:
alwaysApply: true
---
# Swift Best Practices (Lickability-Based)
Based on [Lickability's Swift Best Practices](mdc:https:/github.com/Lickability/swift-best-practices)
## **Code Organization**
- **File Structure:**
- Group related functionality together
- Use MARK comments to organize code sections
- Follow consistent import ordering: Foundation, UIKit, third-party, local modules
- Place extensions in separate files when they add significant functionality
- **Access Control:**
- Use `private` by default, escalate to `fileprivate`, `internal`, `public` as needed
- Prefer `private(set)` for properties that should be readable but not writable externally
- Use `final` for classes that shouldn't be subclassed
```swift
// ✅ DO: Proper access control
final class GameManager {
private let networkService: NetworkService
private(set) var currentGame: Game?
public init(networkService: NetworkService) {
self.networkService = networkService
}
}
// ❌ DON'T: Overly permissive access
class GameManager {
var networkService: NetworkService
var currentGame: Game?
}
```
## **Naming Conventions**
- **Variables and Functions:**
- Use descriptive, self-documenting names
- Prefer clarity over brevity
- Use camelCase for variables, functions, and properties
- Use PascalCase for types, protocols, and enums
```swift
// ✅ DO: Clear, descriptive naming
func calculateDistanceBetweenPlayers(_ player1: Player, _ player2: Player) -> CLLocationDistance
var isUserWithinSafeZone: Bool
let maximumGameDuration: TimeInterval
// ❌ DON'T: Abbreviated or unclear names
func calcDist(_ p1: Player, _ p2: Player) -> CLLocationDistance
var inSafe: Bool
let maxDur: TimeInterval
```
- **Constants and Static Properties:**
- Use descriptive names that explain the purpose
- Group related constants in enums or structs
```swift
// ✅ DO: Well-organized constants
enum GameConstants {
static let defaultSafeZoneRadius: CLLocationDistance = 100.0
static let maximumPlayersPerGame = 20
static let gameTimeoutInterval: TimeInterval = 3600
}
// ❌ DON'T: Magic numbers or unclear constants
let radius = 100.0
let maxPlayers = 20
```
## **Optionals and Safety**
- **Optional Handling:**
- Prefer safe unwrapping over force unwrapping
- Use guard statements for early returns
- Use nil coalescing operator when appropriate
```swift
// ✅ DO: Safe optional handling
guard let user = currentUser else {
logger.error("No current user available")
return
}
let displayName = user.displayName ?? "Anonymous"
// ❌ DON'T: Force unwrapping
let user = currentUser!
let displayName = user.displayName!
```
- **Implicitly Unwrapped Optionals:**
- Avoid unless absolutely necessary (IBOutlets, dependency injection)
- Document why they're needed when used
## **Error Handling**
- **Use Result Types:**
- Prefer Result<Success, Failure> for async operations
- Use descriptive error types
```swift
// ✅ DO: Proper error handling
enum GameError: Error, LocalizedError {
case playerNotFound
case gameNotActive
case networkUnavailable
var errorDescription: String? {
switch self {
case .playerNotFound:
return "Player not found in current game"
case .gameNotActive:
return "No active game session"
case .networkUnavailable:
return "Network connection unavailable"
}
}
}
func joinGame(with code: String) -> Result<Game, GameError> {
// Implementation
}
```
## **SwiftUI Best Practices**
- **View Composition:**
- Break down complex views into smaller, reusable components
- Use ViewBuilder for conditional content
- Prefer computed properties over functions for simple transformations
```swift
// ✅ DO: Composable views
struct GameStatusView: View {
let game: Game
var body: some View {
VStack(spacing: 16) {
gameHeaderView
playerListView
gameActionsView
}
}
@ViewBuilder
private var gameHeaderView: some View {
HStack {
Text(game.name)
.font(.headlineLarge)
Spacer()
GameStatusBadge(status: game.status)
}
}
}
```
- **State Management:**
- Use @State for local view state
- Use @StateObject for view-owned objects
- Use @ObservedObject for externally-owned objects
- Prefer @Published properties in ObservableObject
```swift
// ✅ DO: Proper state management
class GameViewModel: ObservableObject {
@Published var currentGame: Game?
@Published var isLoading = false
@Published var errorMessage: String?
private let gameService: GameService
init(gameService: GameService) {
self.gameService = gameService
}
}
struct GameView: View {
@StateObject private var viewModel = GameViewModel(gameService: GameService())
@State private var showingJoinSheet = false
}
```
## **Protocols and Extensions**
- **Protocol Design:**
- Keep protocols focused and cohesive
- Use protocol extensions for default implementations
- Prefer composition over inheritance
```swift
// ✅ DO: Focused protocols
protocol GameEventHandler {
func handlePlayerJoined(_ player: Player)
func handlePlayerLeft(_ player: Player)
func handleGameEnded()
}
extension GameEventHandler {
func handlePlayerLeft(_ player: Player) {
// Default implementation
print("Player \(player.name) left the game")
}
}
```
- **Extensions:**
- Use extensions to organize code by functionality
- Place protocol conformance in separate extensions
- Use MARK comments to organize extension sections
```swift
// ✅ DO: Organized extensions
extension GameManager {
// MARK: - Game Lifecycle
func startGame() { /* implementation */ }
func endGame() { /* implementation */ }
}
extension GameManager: GameEventHandler {
// MARK: - GameEventHandler
func handlePlayerJoined(_ player: Player) {
// implementation
}
}
```
## **Documentation and Comments**
- **Documentation:**
- Use /// for public APIs
- Include parameter descriptions and return values
- Document complex algorithms or business logic
```swift
/// Calculates the distance between two players and determines if they're within elimination range
/// - Parameters:
/// - hunter: The player attempting elimination
/// - target: The player being targeted
/// - Returns: The distance in meters, or nil if location data is unavailable
func calculateEliminationDistance(hunter: Player, target: Player) -> CLLocationDistance? {
// Implementation
}
```
- **Comments:**
- Use comments to explain "why", not "what"
- Keep comments up-to-date with code changes
- Use TODO comments with issue links (enforced by SwiftLint)
```swift
// ✅ DO: Explain the reasoning
// We cache the user's location for 30 seconds to reduce battery drain
// while still maintaining reasonable accuracy for gameplay
private let locationCacheTimeout: TimeInterval = 30
// TODO: Implement push notification retry logic - https://github.com/org/repo/issues/123
```
## **Testing Considerations**
- **Testable Code:**
- Use dependency injection
- Avoid static dependencies
- Make methods pure when possible
```swift
// ✅ DO: Testable design
class LocationService {
private let locationManager: CLLocationManager
init(locationManager: CLLocationManager = CLLocationManager()) {
self.locationManager = locationManager
}
}
// ❌ DON'T: Hard dependencies
class LocationService {
private let locationManager = CLLocationManager()
}
```
## **Performance Guidelines**
- **Memory Management:**
- Use weak references to break retain cycles
- Prefer value types (structs) when appropriate
- Be mindful of capture lists in closures
```swift
// ✅ DO: Proper memory management
class GameViewController: UIViewController {
private var gameService: GameService?
override func viewDidLoad() {
super.viewDidLoad()
gameService?.onGameUpdate = { [weak self] game in
self?.updateUI(with: game)
}
}
}
```
- **Lazy Loading:**
- Use lazy properties for expensive computations
- Consider lazy loading for UI components
```swift
// ✅ DO: Lazy initialization
class GameMapView: UIView {
private lazy var mapView: MKMapView = {
let map = MKMapView()
map.delegate = self
map.showsUserLocation = true
return map
}()
}
```
TypeScript Best Practices
Cursor IDE rules and conventions for AI-assisted development.
by AgentHub Crawler
Best Practices
Cursor IDE rules and conventions for AI-assisted development.
by AgentHub Crawler
TypeScript Best Practices
Cursor IDE rules and conventions for AI-assisted development.
by AgentHub Crawler
Shadcn UI Best Practices
This document outlines best practices for developing with Shadcn UI, covering code organization, common patterns, performance considerations, security, testing, common pitfalls, and tooling.
Sign in to leave a comment.
by AgentHub Crawler