agentic-team-templates 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/package.json +1 -1
- package/src/index.js +22 -2
- package/src/index.test.js +5 -0
- package/templates/cpp-expert/.cursorrules/concurrency.md +211 -0
- package/templates/cpp-expert/.cursorrules/error-handling.md +170 -0
- package/templates/cpp-expert/.cursorrules/memory-and-ownership.md +220 -0
- package/templates/cpp-expert/.cursorrules/modern-cpp.md +211 -0
- package/templates/cpp-expert/.cursorrules/overview.md +87 -0
- package/templates/cpp-expert/.cursorrules/performance.md +223 -0
- package/templates/cpp-expert/.cursorrules/testing.md +230 -0
- package/templates/cpp-expert/.cursorrules/tooling.md +312 -0
- package/templates/cpp-expert/CLAUDE.md +242 -0
- package/templates/csharp-expert/.cursorrules/aspnet-core.md +311 -0
- package/templates/csharp-expert/.cursorrules/async-patterns.md +206 -0
- package/templates/csharp-expert/.cursorrules/dependency-injection.md +206 -0
- package/templates/csharp-expert/.cursorrules/error-handling.md +235 -0
- package/templates/csharp-expert/.cursorrules/language-features.md +204 -0
- package/templates/csharp-expert/.cursorrules/overview.md +92 -0
- package/templates/csharp-expert/.cursorrules/performance.md +251 -0
- package/templates/csharp-expert/.cursorrules/testing.md +282 -0
- package/templates/csharp-expert/.cursorrules/tooling.md +254 -0
- package/templates/csharp-expert/CLAUDE.md +360 -0
- package/templates/java-expert/.cursorrules/concurrency.md +209 -0
- package/templates/java-expert/.cursorrules/error-handling.md +205 -0
- package/templates/java-expert/.cursorrules/modern-java.md +216 -0
- package/templates/java-expert/.cursorrules/overview.md +81 -0
- package/templates/java-expert/.cursorrules/performance.md +239 -0
- package/templates/java-expert/.cursorrules/persistence.md +262 -0
- package/templates/java-expert/.cursorrules/spring-boot.md +262 -0
- package/templates/java-expert/.cursorrules/testing.md +272 -0
- package/templates/java-expert/.cursorrules/tooling.md +301 -0
- package/templates/java-expert/CLAUDE.md +325 -0
- package/templates/javascript-expert/.cursorrules/overview.md +5 -3
- package/templates/javascript-expert/.cursorrules/typescript-deep-dive.md +348 -0
- package/templates/javascript-expert/CLAUDE.md +34 -3
- package/templates/kotlin-expert/.cursorrules/coroutines.md +237 -0
- package/templates/kotlin-expert/.cursorrules/error-handling.md +149 -0
- package/templates/kotlin-expert/.cursorrules/frameworks.md +227 -0
- package/templates/kotlin-expert/.cursorrules/language-features.md +231 -0
- package/templates/kotlin-expert/.cursorrules/overview.md +77 -0
- package/templates/kotlin-expert/.cursorrules/performance.md +185 -0
- package/templates/kotlin-expert/.cursorrules/testing.md +213 -0
- package/templates/kotlin-expert/.cursorrules/tooling.md +258 -0
- package/templates/kotlin-expert/CLAUDE.md +276 -0
- package/templates/swift-expert/.cursorrules/concurrency.md +230 -0
- package/templates/swift-expert/.cursorrules/error-handling.md +213 -0
- package/templates/swift-expert/.cursorrules/language-features.md +246 -0
- package/templates/swift-expert/.cursorrules/overview.md +88 -0
- package/templates/swift-expert/.cursorrules/performance.md +260 -0
- package/templates/swift-expert/.cursorrules/swiftui.md +260 -0
- package/templates/swift-expert/.cursorrules/testing.md +286 -0
- package/templates/swift-expert/.cursorrules/tooling.md +285 -0
- package/templates/swift-expert/CLAUDE.md +275 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Swift Language Features
|
|
2
|
+
|
|
3
|
+
Optionals, value types, enums, generics, and protocol-oriented design. The type system is your strongest tool.
|
|
4
|
+
|
|
5
|
+
## Optionals
|
|
6
|
+
|
|
7
|
+
```swift
|
|
8
|
+
// Guard let — early exit pattern (preferred)
|
|
9
|
+
guard let user = fetchUser(id: userId) else {
|
|
10
|
+
throw AppError.userNotFound(userId)
|
|
11
|
+
}
|
|
12
|
+
// user is non-optional from here
|
|
13
|
+
|
|
14
|
+
// If let — conditional binding
|
|
15
|
+
if let email = user.email {
|
|
16
|
+
sendNotification(to: email)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Optional chaining
|
|
20
|
+
let street = user.address?.street?.uppercased()
|
|
21
|
+
|
|
22
|
+
// Nil coalescing
|
|
23
|
+
let displayName = user.nickname ?? user.fullName ?? "Anonymous"
|
|
24
|
+
|
|
25
|
+
// Optional map/flatMap
|
|
26
|
+
let uppercasedEmail = user.email.map { $0.uppercased() }
|
|
27
|
+
let parsed: URL? = urlString.flatMap { URL(string: $0) }
|
|
28
|
+
|
|
29
|
+
// Never: force-unwrap without proof
|
|
30
|
+
// user.email! — use guard/if let instead
|
|
31
|
+
// Only acceptable: IBOutlets (UIKit), known-safe literals
|
|
32
|
+
let url = URL(string: "https://api.example.com")! // Known-safe literal
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Value Types vs Reference Types
|
|
36
|
+
|
|
37
|
+
```swift
|
|
38
|
+
// Prefer structs — value semantics, no shared mutable state
|
|
39
|
+
struct User: Identifiable, Sendable {
|
|
40
|
+
let id: UUID
|
|
41
|
+
var name: String
|
|
42
|
+
var email: String
|
|
43
|
+
var preferences: Preferences
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Use classes only when you need:
|
|
47
|
+
// 1. Identity (object === object)
|
|
48
|
+
// 2. Reference semantics (shared state)
|
|
49
|
+
// 3. Inheritance from ObjC classes
|
|
50
|
+
// 4. Deinitializers
|
|
51
|
+
class NetworkSession {
|
|
52
|
+
private var urlSession: URLSession
|
|
53
|
+
deinit { urlSession.invalidateAndCancel() }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Copy-on-write for large value types
|
|
57
|
+
struct LargeCollection<Element> {
|
|
58
|
+
private var storage: Storage // Reference type internally
|
|
59
|
+
// Implement COW manually only when profiling shows need
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Enums
|
|
64
|
+
|
|
65
|
+
```swift
|
|
66
|
+
// Enums with associated values — model state precisely
|
|
67
|
+
enum LoadingState<T> {
|
|
68
|
+
case idle
|
|
69
|
+
case loading
|
|
70
|
+
case loaded(T)
|
|
71
|
+
case failed(Error)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Exhaustive switch — compiler enforces all cases
|
|
75
|
+
func render(state: LoadingState<[User]>) -> some View {
|
|
76
|
+
switch state {
|
|
77
|
+
case .idle:
|
|
78
|
+
EmptyView()
|
|
79
|
+
case .loading:
|
|
80
|
+
ProgressView()
|
|
81
|
+
case .loaded(let users):
|
|
82
|
+
UserListView(users: users)
|
|
83
|
+
case .failed(let error):
|
|
84
|
+
ErrorView(error: error)
|
|
85
|
+
}
|
|
86
|
+
// No default needed — compiler verifies exhaustiveness
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// String-backed enums for API
|
|
90
|
+
enum UserRole: String, Codable, CaseIterable {
|
|
91
|
+
case admin
|
|
92
|
+
case editor
|
|
93
|
+
case viewer
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Enums as namespaces
|
|
97
|
+
enum Constants {
|
|
98
|
+
static let maxRetries = 3
|
|
99
|
+
static let defaultTimeout: TimeInterval = 30
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Protocols and Extensions
|
|
104
|
+
|
|
105
|
+
```swift
|
|
106
|
+
// Small, focused protocols
|
|
107
|
+
protocol Identifiable {
|
|
108
|
+
associatedtype ID: Hashable
|
|
109
|
+
var id: ID { get }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
protocol Displayable {
|
|
113
|
+
var displayName: String { get }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Default implementations
|
|
117
|
+
extension Displayable where Self: User {
|
|
118
|
+
var displayName: String { "\(firstName) \(lastName)" }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Protocol composition
|
|
122
|
+
func showProfile(for entity: Identifiable & Displayable) {
|
|
123
|
+
print("\(entity.id): \(entity.displayName)")
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Constrained extensions
|
|
127
|
+
extension Array where Element: Numeric {
|
|
128
|
+
var sum: Element { reduce(0, +) }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
extension Collection where Element: Identifiable {
|
|
132
|
+
func element(withId id: Element.ID) -> Element? {
|
|
133
|
+
first { $0.id == id }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Generics
|
|
139
|
+
|
|
140
|
+
```swift
|
|
141
|
+
// Generic functions
|
|
142
|
+
func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T {
|
|
143
|
+
try JSONDecoder().decode(type, from: data)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Generic types with constraints
|
|
147
|
+
struct Repository<Entity: Identifiable & Codable> {
|
|
148
|
+
private var storage: [Entity.ID: Entity] = [:]
|
|
149
|
+
|
|
150
|
+
mutating func save(_ entity: Entity) {
|
|
151
|
+
storage[entity.id] = entity
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
func find(by id: Entity.ID) -> Entity? {
|
|
155
|
+
storage[id]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Opaque return types (some)
|
|
160
|
+
func makeView() -> some View {
|
|
161
|
+
VStack {
|
|
162
|
+
Text("Hello")
|
|
163
|
+
Image(systemName: "star")
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Primary associated types (Swift 5.7+)
|
|
168
|
+
func processCollection(_ items: some Collection<User>) { /* ... */ }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Property Wrappers
|
|
172
|
+
|
|
173
|
+
```swift
|
|
174
|
+
// Standard property wrappers
|
|
175
|
+
@Published var users: [User] = []
|
|
176
|
+
@State private var isPresented = false
|
|
177
|
+
@Binding var selectedTab: Tab
|
|
178
|
+
@Environment(\.dismiss) var dismiss
|
|
179
|
+
@AppStorage("darkMode") var isDarkMode = false
|
|
180
|
+
|
|
181
|
+
// Custom property wrapper
|
|
182
|
+
@propertyWrapper
|
|
183
|
+
struct Clamped<Value: Comparable> {
|
|
184
|
+
private var value: Value
|
|
185
|
+
let range: ClosedRange<Value>
|
|
186
|
+
|
|
187
|
+
var wrappedValue: Value {
|
|
188
|
+
get { value }
|
|
189
|
+
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
|
|
193
|
+
self.range = range
|
|
194
|
+
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
struct AudioSettings {
|
|
199
|
+
@Clamped(0...100) var volume: Int = 50
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Result Builders
|
|
204
|
+
|
|
205
|
+
```swift
|
|
206
|
+
// SwiftUI uses @ViewBuilder
|
|
207
|
+
@ViewBuilder
|
|
208
|
+
func content(for state: LoadingState<User>) -> some View {
|
|
209
|
+
switch state {
|
|
210
|
+
case .loading:
|
|
211
|
+
ProgressView()
|
|
212
|
+
case .loaded(let user):
|
|
213
|
+
Text(user.name)
|
|
214
|
+
default:
|
|
215
|
+
EmptyView()
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Anti-Patterns
|
|
221
|
+
|
|
222
|
+
```swift
|
|
223
|
+
// Never: force-unwrapping optionals carelessly
|
|
224
|
+
let name = user.name! // Crash if nil
|
|
225
|
+
// Use: guard let name = user.name else { return }
|
|
226
|
+
|
|
227
|
+
// Never: class where struct suffices
|
|
228
|
+
class Point { var x: Double; var y: Double }
|
|
229
|
+
// Use: struct Point { var x: Double; var y: Double }
|
|
230
|
+
|
|
231
|
+
// Never: stringly-typed APIs
|
|
232
|
+
func fetchData(endpoint: String) { /* ... */ }
|
|
233
|
+
// Use: enum Endpoint { case users; case orders }
|
|
234
|
+
|
|
235
|
+
// Never: Any/AnyObject without cause
|
|
236
|
+
func process(_ items: [Any]) { /* ... */ }
|
|
237
|
+
// Use: generics or protocols
|
|
238
|
+
|
|
239
|
+
// Never: deeply nested if/let chains
|
|
240
|
+
if let a = optionalA {
|
|
241
|
+
if let b = a.optionalB {
|
|
242
|
+
if let c = b.optionalC { /* ... */ }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Use: guard let with early return, or optional chaining
|
|
246
|
+
```
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Swift Expert Overview
|
|
2
|
+
|
|
3
|
+
Principal-level Swift engineering. Deep language mastery, protocol-oriented design, concurrency, and Apple platform expertise.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
This guide applies to:
|
|
8
|
+
- iOS and iPadOS applications (UIKit, SwiftUI)
|
|
9
|
+
- macOS applications (AppKit, SwiftUI)
|
|
10
|
+
- watchOS and tvOS applications
|
|
11
|
+
- Server-side Swift (Vapor, Hummingbird)
|
|
12
|
+
- Swift packages and frameworks
|
|
13
|
+
- Command-line tools
|
|
14
|
+
|
|
15
|
+
## Core Philosophy
|
|
16
|
+
|
|
17
|
+
Swift is a safe, fast, and expressive language. Use its type system to make invalid states unrepresentable.
|
|
18
|
+
|
|
19
|
+
- **Safety is the foundation.** Optionals, value types, and the compiler are your first line of defense
|
|
20
|
+
- **Protocol-oriented design.** Prefer protocols and composition over class inheritance
|
|
21
|
+
- **Value semantics by default.** Structs over classes unless you need reference semantics
|
|
22
|
+
- **Concurrency is structured.** async/await, actors, and task groups — not GCD callbacks
|
|
23
|
+
- **Expressiveness without obscurity.** Clear is better than clever
|
|
24
|
+
- **If you don't know, say so.** Admitting uncertainty is professional
|
|
25
|
+
|
|
26
|
+
## Key Principles
|
|
27
|
+
|
|
28
|
+
1. **Optionals Are Not Enemies** — Embrace `Optional`. Never force-unwrap without proof. Use `guard`, `if let`, `map`, `flatMap`
|
|
29
|
+
2. **Value Types by Default** — Structs, enums, tuples. Classes only when identity or reference semantics are required
|
|
30
|
+
3. **Protocol-Oriented Design** — Small, focused protocols. Default implementations via extensions. Composition over inheritance
|
|
31
|
+
4. **Structured Concurrency** — `async`/`await`, `TaskGroup`, actors. No completion handler callbacks in new code
|
|
32
|
+
5. **Exhaustive Pattern Matching** — `switch` on enums is exhaustive. The compiler enforces completeness
|
|
33
|
+
|
|
34
|
+
## Project Structure
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
MyApp/
|
|
38
|
+
├── Sources/
|
|
39
|
+
│ ├── App/
|
|
40
|
+
│ │ ├── MyAppApp.swift
|
|
41
|
+
│ │ └── AppDelegate.swift
|
|
42
|
+
│ ├── Features/
|
|
43
|
+
│ │ ├── Auth/
|
|
44
|
+
│ │ │ ├── Views/
|
|
45
|
+
│ │ │ ├── ViewModels/
|
|
46
|
+
│ │ │ └── Models/
|
|
47
|
+
│ │ └── Home/
|
|
48
|
+
│ ├── Core/
|
|
49
|
+
│ │ ├── Networking/
|
|
50
|
+
│ │ ├── Persistence/
|
|
51
|
+
│ │ └── Extensions/
|
|
52
|
+
│ └── Shared/
|
|
53
|
+
│ ├── Components/
|
|
54
|
+
│ └── Utilities/
|
|
55
|
+
├── Tests/
|
|
56
|
+
│ ├── UnitTests/
|
|
57
|
+
│ ├── IntegrationTests/
|
|
58
|
+
│ └── UITests/
|
|
59
|
+
├── Package.swift (or .xcodeproj)
|
|
60
|
+
└── README.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Design Guidelines
|
|
64
|
+
|
|
65
|
+
Follow Swift's official API Design Guidelines:
|
|
66
|
+
|
|
67
|
+
- **Clarity at the point of use** is the most important goal
|
|
68
|
+
- **Omit needless words** — every word should convey information
|
|
69
|
+
- **Name according to roles**, not types: `let greeting: String` not `let greetingString: String`
|
|
70
|
+
- **Label closure parameters**: `func filter(_ isIncluded: (Element) -> Bool)`
|
|
71
|
+
- **Boolean properties** read as assertions: `isEmpty`, `hasChildren`, `canBecomeFirstResponder`
|
|
72
|
+
- **Mutating/nonmutating pairs**: `sort()`/`sorted()`, `append()`/`appending()`
|
|
73
|
+
- **Protocols describing capabilities** end in `-able`, `-ible`, or `-ing`: `Equatable`, `Codable`, `Sendable`
|
|
74
|
+
|
|
75
|
+
## Definition of Done
|
|
76
|
+
|
|
77
|
+
A Swift feature is complete when:
|
|
78
|
+
|
|
79
|
+
- [ ] Compiles with zero warnings
|
|
80
|
+
- [ ] All tests pass (unit + UI)
|
|
81
|
+
- [ ] No force-unwraps (`!`) without documented justification
|
|
82
|
+
- [ ] No `var` where `let` suffices
|
|
83
|
+
- [ ] Proper access control (`private`, `internal`, `public`)
|
|
84
|
+
- [ ] Concurrency code uses structured concurrency (no raw GCD in new code)
|
|
85
|
+
- [ ] SwiftLint reports zero violations
|
|
86
|
+
- [ ] No retain cycles (weak/unowned references verified)
|
|
87
|
+
- [ ] Accessibility labels on all interactive UI elements
|
|
88
|
+
- [ ] Code reviewed and approved
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Swift Performance
|
|
2
|
+
|
|
3
|
+
Profile first. Understand ARC, value types, and Instruments. Optimize what matters.
|
|
4
|
+
|
|
5
|
+
## Profile Before Optimizing
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Instruments — always profile before optimizing
|
|
9
|
+
# Time Profiler: CPU hotspots
|
|
10
|
+
# Allocations: memory usage and leaks
|
|
11
|
+
# Leaks: retain cycles
|
|
12
|
+
# Network: request analysis
|
|
13
|
+
# Core Animation: rendering performance
|
|
14
|
+
|
|
15
|
+
# Xcode: Product → Profile (⌘I)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Value Types and Copy-on-Write
|
|
19
|
+
|
|
20
|
+
```swift
|
|
21
|
+
// Structs are stack-allocated (when possible) and value-copied
|
|
22
|
+
// But Swift uses COW for standard library collections
|
|
23
|
+
var array1 = [1, 2, 3]
|
|
24
|
+
var array2 = array1 // No copy yet — shared storage
|
|
25
|
+
array2.append(4) // Copy happens here (COW trigger)
|
|
26
|
+
|
|
27
|
+
// Custom COW for large value types
|
|
28
|
+
struct LargeStruct {
|
|
29
|
+
private final class Storage {
|
|
30
|
+
var data: [Int]
|
|
31
|
+
init(data: [Int]) { self.data = data }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private var storage: Storage
|
|
35
|
+
|
|
36
|
+
var data: [Int] {
|
|
37
|
+
get { storage.data }
|
|
38
|
+
set {
|
|
39
|
+
if !isKnownUniquelyReferenced(&storage) {
|
|
40
|
+
storage = Storage(data: newValue)
|
|
41
|
+
} else {
|
|
42
|
+
storage.data = newValue
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## ARC and Retain Cycles
|
|
50
|
+
|
|
51
|
+
```swift
|
|
52
|
+
// Weak references — break retain cycles
|
|
53
|
+
class ViewController: UIViewController {
|
|
54
|
+
private var cancellable: AnyCancellable?
|
|
55
|
+
|
|
56
|
+
func subscribe() {
|
|
57
|
+
cancellable = publisher
|
|
58
|
+
.sink { [weak self] value in // weak self!
|
|
59
|
+
self?.handleValue(value)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Unowned — when you guarantee the reference outlives the closure
|
|
65
|
+
class Parent {
|
|
66
|
+
let child: Child
|
|
67
|
+
|
|
68
|
+
init() {
|
|
69
|
+
child = Child()
|
|
70
|
+
child.onComplete = { [unowned self] in
|
|
71
|
+
self.handleCompletion() // Crashes if self is deallocated
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Capture lists — be explicit
|
|
77
|
+
Task { [weak self, userId = self.user.id] in
|
|
78
|
+
guard let self else { return }
|
|
79
|
+
let data = try await self.fetch(userId: userId)
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Collection Performance
|
|
84
|
+
|
|
85
|
+
```swift
|
|
86
|
+
// Reserve capacity for known sizes
|
|
87
|
+
var results: [ProcessedItem] = []
|
|
88
|
+
results.reserveCapacity(items.count)
|
|
89
|
+
|
|
90
|
+
// Use lazy for chained operations on large collections
|
|
91
|
+
let names = users.lazy
|
|
92
|
+
.filter { $0.isActive }
|
|
93
|
+
.map { $0.fullName }
|
|
94
|
+
.prefix(10)
|
|
95
|
+
// Operations only execute when iterated
|
|
96
|
+
|
|
97
|
+
// ContiguousArray for non-class element types
|
|
98
|
+
let numbers = ContiguousArray<Int>(repeating: 0, count: 1000)
|
|
99
|
+
// Guaranteed contiguous memory layout — better cache performance
|
|
100
|
+
|
|
101
|
+
// Set for membership tests
|
|
102
|
+
let activeIds = Set(activeUsers.map(\.id)) // O(1) lookup
|
|
103
|
+
let filtered = orders.filter { activeIds.contains($0.userId) }
|
|
104
|
+
|
|
105
|
+
// Dictionary for keyed access
|
|
106
|
+
let userById = Dictionary(uniqueKeysWithValues: users.map { ($0.id, $0) })
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## String Performance
|
|
110
|
+
|
|
111
|
+
```swift
|
|
112
|
+
// String is a value type with COW
|
|
113
|
+
// UTF-8 encoded internally — character access is O(n)
|
|
114
|
+
|
|
115
|
+
// Prefer Substring over creating new Strings
|
|
116
|
+
let greeting = "Hello, World!"
|
|
117
|
+
let hello = greeting.prefix(5) // Substring — shares storage
|
|
118
|
+
|
|
119
|
+
// Convert to String only when needed for storage
|
|
120
|
+
let stored = String(hello) // Creates independent copy
|
|
121
|
+
|
|
122
|
+
// Use string interpolation — optimized by compiler
|
|
123
|
+
let message = "User \(user.name) logged in" // Efficient
|
|
124
|
+
|
|
125
|
+
// For heavy concatenation
|
|
126
|
+
var result = ""
|
|
127
|
+
result.reserveCapacity(estimatedLength)
|
|
128
|
+
for item in items {
|
|
129
|
+
result += item.description
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## SwiftUI Performance
|
|
134
|
+
|
|
135
|
+
```swift
|
|
136
|
+
// Avoid unnecessary view recomputation
|
|
137
|
+
struct UserRow: View {
|
|
138
|
+
let user: User // Prefer let over @State for display-only data
|
|
139
|
+
|
|
140
|
+
var body: some View {
|
|
141
|
+
HStack {
|
|
142
|
+
AvatarView(url: user.avatarURL)
|
|
143
|
+
Text(user.name)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Equatable conformance to skip redundant diffs
|
|
149
|
+
struct ExpensiveView: View, Equatable {
|
|
150
|
+
let data: ChartData
|
|
151
|
+
|
|
152
|
+
static func == (lhs: Self, rhs: Self) -> Bool {
|
|
153
|
+
lhs.data.id == rhs.data.id && lhs.data.version == rhs.data.version
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var body: some View {
|
|
157
|
+
ChartRenderer(data: data) // Expensive
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Use @Observable over ObservableObject (iOS 17+)
|
|
162
|
+
// @Observable tracks property-level access — fewer view updates
|
|
163
|
+
|
|
164
|
+
// Lazy stacks for large lists
|
|
165
|
+
ScrollView {
|
|
166
|
+
LazyVStack { // Only creates visible views
|
|
167
|
+
ForEach(items) { item in
|
|
168
|
+
ItemRow(item: item)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Concurrency Performance
|
|
175
|
+
|
|
176
|
+
```swift
|
|
177
|
+
// Limit concurrent work
|
|
178
|
+
func processImages(_ urls: [URL]) async throws -> [UIImage] {
|
|
179
|
+
try await withThrowingTaskGroup(of: UIImage.self) { group in
|
|
180
|
+
let maxConcurrency = ProcessInfo.processInfo.activeProcessorCount
|
|
181
|
+
|
|
182
|
+
var results: [UIImage] = []
|
|
183
|
+
results.reserveCapacity(urls.count)
|
|
184
|
+
|
|
185
|
+
for (index, url) in urls.enumerated() {
|
|
186
|
+
if index >= maxConcurrency {
|
|
187
|
+
if let image = try await group.next() {
|
|
188
|
+
results.append(image)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
group.addTask { try await downloadImage(from: url) }
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
for try await image in group {
|
|
195
|
+
results.append(image)
|
|
196
|
+
}
|
|
197
|
+
return results
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Avoid unnecessary actor hops
|
|
202
|
+
actor DataStore {
|
|
203
|
+
private var items: [Item] = []
|
|
204
|
+
|
|
205
|
+
// Batch operations reduce actor hops
|
|
206
|
+
func addAll(_ newItems: [Item]) {
|
|
207
|
+
items.append(contentsOf: newItems) // Single hop
|
|
208
|
+
}
|
|
209
|
+
// Instead of calling add(_:) in a loop — one hop per call
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Memory Management
|
|
214
|
+
|
|
215
|
+
```swift
|
|
216
|
+
// Autoreleasepool for tight loops with ObjC objects
|
|
217
|
+
func processLargeDataset() {
|
|
218
|
+
for batch in dataset.chunks(ofCount: 100) {
|
|
219
|
+
autoreleasepool {
|
|
220
|
+
let processed = batch.map { transform($0) }
|
|
221
|
+
save(processed)
|
|
222
|
+
}
|
|
223
|
+
// Memory released each iteration
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Avoid strong reference cycles in closures
|
|
228
|
+
class NetworkManager {
|
|
229
|
+
var onComplete: ((Result<Data, Error>) -> Void)?
|
|
230
|
+
|
|
231
|
+
deinit {
|
|
232
|
+
onComplete = nil // Break cycle on dealloc
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Anti-Patterns
|
|
238
|
+
|
|
239
|
+
```swift
|
|
240
|
+
// Never: premature optimization without profiling
|
|
241
|
+
// "I think this allocation is slow" — prove it with Instruments
|
|
242
|
+
|
|
243
|
+
// Never: using classes where structs work
|
|
244
|
+
class Point { var x: Double; var y: Double } // Heap allocation
|
|
245
|
+
// Use: struct Point — stack allocation, no ARC overhead
|
|
246
|
+
|
|
247
|
+
// Never: force-unwrapping in hot paths
|
|
248
|
+
array[index]! // Hidden crash waiting to happen
|
|
249
|
+
|
|
250
|
+
// Never: string concatenation with + in loops
|
|
251
|
+
var result = ""
|
|
252
|
+
for item in items { result = result + item.name } // O(n²)
|
|
253
|
+
// Use: reserveCapacity + append, or joined()
|
|
254
|
+
|
|
255
|
+
// Never: capturing self strongly in long-lived closures
|
|
256
|
+
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
|
|
257
|
+
self.update() // Retain cycle
|
|
258
|
+
}
|
|
259
|
+
// Use: [weak self]
|
|
260
|
+
```
|