swift-code-reviewer-skill 1.0.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.
@@ -0,0 +1,928 @@
1
+ # Swift Quality Checklist
2
+
3
+ This checklist covers Swift 6+ language features, concurrency patterns, error handling, optionals, access control, and naming conventions. Use this to ensure code follows modern Swift best practices.
4
+
5
+ ---
6
+
7
+ ## 1. Concurrency & Swift 6 Patterns
8
+
9
+ ### 1.1 Actor Isolation
10
+
11
+ **Check for:**
12
+ - [ ] UI-related classes marked with `@MainActor`
13
+ - [ ] Mutable state properly isolated with actors
14
+ - [ ] No shared mutable state without synchronization
15
+ - [ ] Proper actor isolation boundaries
16
+
17
+ **Examples:**
18
+
19
+ ❌ **Bad: No actor isolation**
20
+ ```swift
21
+ class UserViewModel {
22
+ var users: [User] = [] // ❌ Mutable state without isolation
23
+
24
+ func loadUsers() {
25
+ // Can be called from any thread - data race!
26
+ }
27
+ }
28
+ ```
29
+
30
+ ✅ **Good: Proper MainActor isolation**
31
+ ```swift
32
+ @MainActor
33
+ class UserViewModel: ObservableObject {
34
+ @Published var users: [User] = [] // ✅ MainActor-isolated
35
+
36
+ func loadUsers() async {
37
+ // Always runs on main actor
38
+ }
39
+ }
40
+ ```
41
+
42
+ ✅ **Good: Custom actor for background work**
43
+ ```swift
44
+ actor DatabaseManager {
45
+ private var cache: [String: Data] = [:] // ✅ Actor-isolated
46
+
47
+ func save(_ data: Data, forKey key: String) {
48
+ cache[key] = data
49
+ }
50
+
51
+ func fetch(forKey key: String) -> Data? {
52
+ return cache[key]
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### 1.2 Sendable Conformance
58
+
59
+ **Check for:**
60
+ - [ ] Types crossing actor boundaries conform to Sendable
61
+ - [ ] Value types (struct, enum) are implicitly Sendable
62
+ - [ ] Reference types explicitly marked with Sendable where appropriate
63
+ - [ ] Non-Sendable types properly isolated
64
+
65
+ **Examples:**
66
+
67
+ ❌ **Bad: Non-Sendable type crossing actors**
68
+ ```swift
69
+ class UserData { // ❌ Class without Sendable
70
+ var name: String
71
+ }
72
+
73
+ actor DataStore {
74
+ func save(_ data: UserData) { // ⚠️ Warning: non-Sendable type
75
+ // ...
76
+ }
77
+ }
78
+ ```
79
+
80
+ ✅ **Good: Sendable struct**
81
+ ```swift
82
+ struct UserData: Sendable { // ✅ Value type is Sendable
83
+ let name: String
84
+ }
85
+
86
+ actor DataStore {
87
+ func save(_ data: UserData) { // ✅ OK
88
+ // ...
89
+ }
90
+ }
91
+ ```
92
+
93
+ ✅ **Good: Sendable reference type**
94
+ ```swift
95
+ final class UserData: @unchecked Sendable { // ✅ Explicitly Sendable
96
+ private let lock = NSLock()
97
+ private var _name: String
98
+
99
+ var name: String {
100
+ lock.lock()
101
+ defer { lock.unlock() }
102
+ return _name
103
+ }
104
+ // Thread-safe implementation
105
+ }
106
+ ```
107
+
108
+ ### 1.3 Async/Await Patterns
109
+
110
+ **Check for:**
111
+ - [ ] Async/await used instead of completion handlers
112
+ - [ ] Structured concurrency (Task, TaskGroup) over unstructured
113
+ - [ ] Proper error propagation with async throws
114
+ - [ ] No blocking the main thread
115
+
116
+ **Examples:**
117
+
118
+ ❌ **Bad: Completion handler**
119
+ ```swift
120
+ func fetchUser(id: UUID, completion: @escaping (Result<User, Error>) -> Void) {
121
+ // Old pattern
122
+ }
123
+ ```
124
+
125
+ ✅ **Good: Async/await**
126
+ ```swift
127
+ func fetchUser(id: UUID) async throws -> User {
128
+ let (data, _) = try await URLSession.shared.data(from: url)
129
+ return try JSONDecoder().decode(User.self, from: data)
130
+ }
131
+ ```
132
+
133
+ ❌ **Bad: Unstructured concurrency**
134
+ ```swift
135
+ func loadData() {
136
+ Task { // ❌ Unstructured, no cancellation handling
137
+ await fetchUsers()
138
+ }
139
+ Task {
140
+ await fetchPosts()
141
+ }
142
+ }
143
+ ```
144
+
145
+ ✅ **Good: Structured concurrency**
146
+ ```swift
147
+ func loadData() async {
148
+ await withTaskGroup(of: Void.self) { group in
149
+ group.addTask { await self.fetchUsers() }
150
+ group.addTask { await self.fetchPosts() }
151
+ // All tasks complete before function returns
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### 1.4 Data Race Prevention
157
+
158
+ **Check for:**
159
+ - [ ] No mutable global state
160
+ - [ ] No mutable static properties (use actors or @MainActor)
161
+ - [ ] No unsynchronized shared state between actors
162
+ - [ ] Proper use of Task-local values
163
+
164
+ **Examples:**
165
+
166
+ ❌ **Bad: Mutable global state**
167
+ ```swift
168
+ var currentUser: User? // ❌ Mutable global - data race!
169
+
170
+ func updateUser(_ user: User) {
171
+ currentUser = user // ❌ Can be called from multiple threads
172
+ }
173
+ ```
174
+
175
+ ✅ **Good: Actor-isolated state**
176
+ ```swift
177
+ @MainActor
178
+ final class UserManager {
179
+ static let shared = UserManager()
180
+ private(set) var currentUser: User? // ✅ MainActor-isolated
181
+
182
+ func updateUser(_ user: User) {
183
+ currentUser = user // ✅ Always on main actor
184
+ }
185
+ }
186
+ ```
187
+
188
+ ✅ **Good: Task-local value**
189
+ ```swift
190
+ enum RequestID {
191
+ @TaskLocal static var current: UUID?
192
+ }
193
+
194
+ func processRequest() async {
195
+ await RequestID.$current.withValue(UUID()) {
196
+ await handleRequest() // Has access to RequestID.current
197
+ }
198
+ }
199
+ ```
200
+
201
+ ### 1.5 Migration to Swift 6
202
+
203
+ **Check for:**
204
+ - [ ] Gradual migration approach (per-module or per-file)
205
+ - [ ] Swift 6 language mode enabled incrementally
206
+ - [ ] Concurrency warnings addressed
207
+ - [ ] Deprecated APIs replaced
208
+
209
+ **Migration Checklist:**
210
+ ```swift
211
+ // Enable Swift 6 mode in Build Settings
212
+ // SWIFT_VERSION = 6.0
213
+
214
+ // Or per-file
215
+ // swift-tools-version: 6.0
216
+
217
+ // Check for warnings
218
+ // Build Settings > Swift Compiler > Code Generation
219
+ // Swift Language Version: Swift 6
220
+ ```
221
+
222
+ ---
223
+
224
+ ## 2. Error Handling
225
+
226
+ ### 2.1 Typed Throws (Swift 6+)
227
+
228
+ **Check for:**
229
+ - [ ] Typed throws for specific error types
230
+ - [ ] Error propagation without generic Error
231
+ - [ ] Meaningful error types
232
+
233
+ **Examples:**
234
+
235
+ ❌ **Bad: Generic Error**
236
+ ```swift
237
+ func fetchUser(id: UUID) throws -> User { // ❌ What errors can it throw?
238
+ // ...
239
+ }
240
+ ```
241
+
242
+ ✅ **Good: Typed throws**
243
+ ```swift
244
+ enum UserError: Error {
245
+ case notFound
246
+ case invalidData
247
+ }
248
+
249
+ func fetchUser(id: UUID) throws(UserError) -> User { // ✅ Explicit error type
250
+ // ...
251
+ }
252
+
253
+ // Caller knows exactly what to catch
254
+ do {
255
+ let user = try fetchUser(id: userID)
256
+ } catch UserError.notFound {
257
+ // Handle not found
258
+ } catch UserError.invalidData {
259
+ // Handle invalid data
260
+ }
261
+ ```
262
+
263
+ ### 2.2 Result Type
264
+
265
+ **Check for:**
266
+ - [ ] Result type for recoverable errors in async contexts
267
+ - [ ] Proper success/failure handling
268
+ - [ ] Meaningful error types
269
+
270
+ **Examples:**
271
+
272
+ ✅ **Good: Result type**
273
+ ```swift
274
+ func fetchUser(id: UUID) async -> Result<User, NetworkError> {
275
+ do {
276
+ let user = try await networkService.fetch(User.self, id: id)
277
+ return .success(user)
278
+ } catch let error as NetworkError {
279
+ return .failure(error)
280
+ } catch {
281
+ return .failure(.unknown)
282
+ }
283
+ }
284
+
285
+ // Usage
286
+ let result = await fetchUser(id: userID)
287
+ switch result {
288
+ case .success(let user):
289
+ // Handle success
290
+ case .failure(let error):
291
+ // Handle error
292
+ }
293
+ ```
294
+
295
+ ### 2.3 Force Try Audit
296
+
297
+ **Check for:**
298
+ - [ ] No `try!` (force try) unless absolutely justified
299
+ - [ ] Proper error handling with do-catch or Result
300
+ - [ ] Comments explaining any necessary force tries
301
+
302
+ **Examples:**
303
+
304
+ ❌ **Bad: Force try**
305
+ ```swift
306
+ let user = try! decoder.decode(User.self, from: data) // ❌ Can crash!
307
+ ```
308
+
309
+ ✅ **Good: Proper error handling**
310
+ ```swift
311
+ do {
312
+ let user = try decoder.decode(User.self, from: data)
313
+ return user
314
+ } catch {
315
+ logger.error("Failed to decode user: \(error)")
316
+ return nil
317
+ }
318
+ ```
319
+
320
+ ✅ **Acceptable: Force try with justification**
321
+ ```swift
322
+ // Static JSON bundled with app - guaranteed to be valid
323
+ let defaultConfig = try! decoder.decode(
324
+ Config.self,
325
+ from: bundledJSONData
326
+ ) // Force try justified: bundled resource
327
+ ```
328
+
329
+ ### 2.4 Error Types
330
+
331
+ **Check for:**
332
+ - [ ] Custom error enums for domain-specific errors
333
+ - [ ] LocalizedError conformance for user-facing errors
334
+ - [ ] Descriptive error messages
335
+
336
+ **Examples:**
337
+
338
+ ✅ **Good: Custom error enum**
339
+ ```swift
340
+ enum LoginError: Error {
341
+ case invalidCredentials
342
+ case accountLocked
343
+ case networkFailure(underlying: Error)
344
+ }
345
+
346
+ extension LoginError: LocalizedError {
347
+ var errorDescription: String? {
348
+ switch self {
349
+ case .invalidCredentials:
350
+ return "Invalid email or password"
351
+ case .accountLocked:
352
+ return "Your account has been locked. Please contact support."
353
+ case .networkFailure:
354
+ return "Network connection failed. Please try again."
355
+ }
356
+ }
357
+ }
358
+ ```
359
+
360
+ ---
361
+
362
+ ## 3. Optionals Handling
363
+
364
+ ### 3.1 Force Unwrap Audit
365
+
366
+ **Check for:**
367
+ - [ ] No force unwrapping (`!`) unless absolutely justified
368
+ - [ ] No forced casting (`as!`)
369
+ - [ ] Comments explaining any necessary force unwraps
370
+
371
+ **Examples:**
372
+
373
+ ❌ **Bad: Force unwrap**
374
+ ```swift
375
+ let user = userRepository.currentUser! // ❌ Can crash!
376
+ let name = user.name!
377
+ ```
378
+
379
+ ✅ **Good: Guard statement**
380
+ ```swift
381
+ guard let user = userRepository.currentUser else {
382
+ logger.error("No current user")
383
+ return
384
+ }
385
+ let name = user.name ?? "Unknown"
386
+ ```
387
+
388
+ ✅ **Good: If-let binding**
389
+ ```swift
390
+ if let user = userRepository.currentUser {
391
+ displayUser(user)
392
+ } else {
393
+ showLoginScreen()
394
+ }
395
+ ```
396
+
397
+ ✅ **Good: Optional chaining**
398
+ ```swift
399
+ let username = userRepository.currentUser?.name ?? "Guest"
400
+ ```
401
+
402
+ ### 3.2 Implicitly Unwrapped Optionals
403
+
404
+ **Check for:**
405
+ - [ ] Avoid `!` declarations unless absolutely necessary
406
+ - [ ] Use regular optionals with proper unwrapping
407
+ - [ ] Only use IUO for IBOutlets or when guaranteed to be set
408
+
409
+ **Examples:**
410
+
411
+ ❌ **Bad: Unnecessary IUO**
412
+ ```swift
413
+ class UserViewModel {
414
+ var authService: AuthService! // ❌ Why IUO?
415
+ }
416
+ ```
417
+
418
+ ✅ **Good: Regular optional or non-optional**
419
+ ```swift
420
+ class UserViewModel {
421
+ let authService: AuthService // ✅ Non-optional with DI
422
+
423
+ init(authService: AuthService) {
424
+ self.authService = authService
425
+ }
426
+ }
427
+ ```
428
+
429
+ ✅ **Acceptable: IBOutlet**
430
+ ```swift
431
+ class LoginViewController: UIViewController {
432
+ @IBOutlet weak var emailTextField: UITextField! // ✅ Acceptable for IB
433
+ }
434
+ ```
435
+
436
+ ### 3.3 Nil Coalescing
437
+
438
+ **Check for:**
439
+ - [ ] Appropriate use of ?? operator
440
+ - [ ] Meaningful default values
441
+ - [ ] No force unwrapping when ?? can be used
442
+
443
+ **Examples:**
444
+
445
+ ✅ **Good: Nil coalescing**
446
+ ```swift
447
+ let username = user.name ?? "Guest"
448
+ let count = items?.count ?? 0
449
+ let config = loadConfig() ?? Config.default
450
+ ```
451
+
452
+ ---
453
+
454
+ ## 4. Access Control
455
+
456
+ ### 4.1 Explicit Access Control
457
+
458
+ **Check for:**
459
+ - [ ] Explicit access control (not relying on defaults)
460
+ - [ ] Private for implementation details
461
+ - [ ] Internal for module-level sharing
462
+ - [ ] Public only for API surface
463
+ - [ ] File-private for file-scoped sharing
464
+
465
+ **Examples:**
466
+
467
+ ❌ **Bad: Implicit access control**
468
+ ```swift
469
+ struct User { // ❌ Implicit internal
470
+ var name: String // ❌ Implicit internal
471
+ }
472
+ ```
473
+
474
+ ✅ **Good: Explicit access control**
475
+ ```swift
476
+ public struct User { // ✅ Explicit public
477
+ public let name: String // ✅ Explicit public
478
+ private let id: UUID // ✅ Explicit private
479
+
480
+ public init(name: String, id: UUID) { // ✅ Public init
481
+ self.name = name
482
+ self.id = id
483
+ }
484
+ }
485
+ ```
486
+
487
+ ### 4.2 Minimizing API Surface
488
+
489
+ **Check for:**
490
+ - [ ] Private by default
491
+ - [ ] Only expose what's necessary
492
+ - [ ] Final classes when inheritance not needed
493
+
494
+ **Examples:**
495
+
496
+ ✅ **Good: Minimal API surface**
497
+ ```swift
498
+ public protocol AuthService {
499
+ func login(email: String, password: String) async throws -> User
500
+ }
501
+
502
+ internal final class DefaultAuthService: AuthService { // ✅ Internal, final
503
+ private let networkClient: NetworkClient // ✅ Private
504
+ private let tokenStorage: TokenStorage // ✅ Private
505
+
506
+ internal init(networkClient: NetworkClient, tokenStorage: TokenStorage) {
507
+ self.networkClient = networkClient
508
+ self.tokenStorage = tokenStorage
509
+ }
510
+
511
+ public func login(email: String, password: String) async throws -> User {
512
+ // Implementation
513
+ }
514
+
515
+ private func validateCredentials(email: String, password: String) -> Bool {
516
+ // ✅ Private helper
517
+ }
518
+ }
519
+ ```
520
+
521
+ ### 4.3 @testable Import
522
+
523
+ **Check for:**
524
+ - [ ] Internal types testable via @testable import
525
+ - [ ] No need to make things public for testing
526
+ - [ ] Proper test target configuration
527
+
528
+ **Examples:**
529
+
530
+ ✅ **Good: Internal types with @testable**
531
+ ```swift
532
+ // In main target
533
+ internal final class UserViewModel { // ✅ Internal
534
+ internal func fetchUsers() async { // ✅ Internal
535
+ // Implementation
536
+ }
537
+ }
538
+
539
+ // In test target
540
+ @testable import MyApp
541
+
542
+ final class UserViewModelTests: XCTestCase {
543
+ func testFetchUsers() async {
544
+ let viewModel = UserViewModel() // ✅ Accessible via @testable
545
+ await viewModel.fetchUsers()
546
+ }
547
+ }
548
+ ```
549
+
550
+ ---
551
+
552
+ ## 5. Naming Conventions
553
+
554
+ ### 5.1 Swift API Design Guidelines
555
+
556
+ **Check for:**
557
+ - [ ] Clear, descriptive names
558
+ - [ ] Proper parameter labels (argument labels + parameter names)
559
+ - [ ] Methods start with verbs
560
+ - [ ] Bool properties start with `is`, `has`, `should`
561
+ - [ ] Types use UpperCamelCase
562
+ - [ ] Properties/variables use lowerCamelCase
563
+
564
+ **Examples:**
565
+
566
+ ❌ **Bad: Poor naming**
567
+ ```swift
568
+ func get(id: UUID) -> User // ❌ Unclear
569
+ func userFetch(uuid: UUID) -> User // ❌ Non-standard
570
+ var loading: Bool // ❌ Unclear
571
+ let max_retry: Int // ❌ Snake case
572
+ ```
573
+
574
+ ✅ **Good: Swift API Design Guidelines**
575
+ ```swift
576
+ func fetchUser(withID id: UUID) async throws -> User // ✅ Clear, verb-based
577
+ var isLoading: Bool // ✅ Bool prefix
578
+ let maximumRetryCount: Int // ✅ Descriptive, camelCase
579
+ ```
580
+
581
+ ### 5.2 Argument Labels
582
+
583
+ **Check for:**
584
+ - [ ] Fluent usage at call site
585
+ - [ ] Argument labels clarify purpose
586
+ - [ ] Omit labels when context is clear
587
+
588
+ **Examples:**
589
+
590
+ ❌ **Bad: Unclear at call site**
591
+ ```swift
592
+ func validate(_ email: String, _ password: String) -> Bool
593
+ // Usage: validate(email, password) // ❌ Unclear
594
+ ```
595
+
596
+ ✅ **Good: Clear argument labels**
597
+ ```swift
598
+ func validate(email: String, password: String) -> Bool
599
+ // Usage: validate(email: userEmail, password: userPassword) // ✅ Clear
600
+ ```
601
+
602
+ ✅ **Good: Fluent external labels**
603
+ ```swift
604
+ func move(from start: Point, to end: Point)
605
+ // Usage: move(from: origin, to: destination) // ✅ Reads like English
606
+ ```
607
+
608
+ ### 5.3 Type Naming
609
+
610
+ **Check for:**
611
+ - [ ] Noun-based type names
612
+ - [ ] Protocols describe capabilities (-able, -ing)
613
+ - [ ] Clear, non-abbreviated names
614
+
615
+ **Examples:**
616
+
617
+ ✅ **Good: Type naming**
618
+ ```swift
619
+ struct User { } // ✅ Noun
620
+ class UserViewModel { } // ✅ Descriptive
621
+ protocol Authenticating { } // ✅ Capability
622
+ protocol DataStorage { } // ✅ Capability
623
+ enum NetworkError { } // ✅ Descriptive
624
+ ```
625
+
626
+ ---
627
+
628
+ ## 6. Type Inference vs Explicit Types
629
+
630
+ ### 6.1 When to Use Type Inference
631
+
632
+ **Check for:**
633
+ - [ ] Type inference for obvious types
634
+ - [ ] Explicit types for clarity
635
+ - [ ] Explicit types for public APIs
636
+
637
+ **Examples:**
638
+
639
+ ✅ **Good: Type inference**
640
+ ```swift
641
+ let username = "john@example.com" // ✅ Obviously String
642
+ let count = items.count // ✅ Obviously Int
643
+ let viewModel = LoginViewModel() // ✅ Clear from initializer
644
+ ```
645
+
646
+ ✅ **Good: Explicit types for clarity**
647
+ ```swift
648
+ let timeout: TimeInterval = 30 // ✅ Clarifies unit (seconds)
649
+ let coordinates: (latitude: Double, longitude: Double) = (37.7749, -122.4194)
650
+ let handler: ((Result<User, Error>) -> Void)? = nil // ✅ Complex type
651
+ ```
652
+
653
+ ✅ **Good: Explicit types in public APIs**
654
+ ```swift
655
+ public func fetchUser(id: UUID) async throws -> User { // ✅ Explicit return
656
+ // Implementation
657
+ }
658
+ ```
659
+
660
+ ---
661
+
662
+ ## 7. Value Types vs Reference Types
663
+
664
+ ### 7.1 Struct vs Class
665
+
666
+ **Check for:**
667
+ - [ ] Structs for value semantics (data models)
668
+ - [ ] Classes for identity and reference semantics
669
+ - [ ] Actors for concurrent mutable state
670
+ - [ ] Protocols for abstraction
671
+
672
+ **Examples:**
673
+
674
+ ✅ **Good: Struct for data**
675
+ ```swift
676
+ struct User { // ✅ Value type for data
677
+ let id: UUID
678
+ let name: String
679
+ let email: String
680
+ }
681
+ ```
682
+
683
+ ✅ **Good: Class for identity**
684
+ ```swift
685
+ @MainActor
686
+ final class UserViewModel: ObservableObject { // ✅ Reference type for state
687
+ @Published var users: [User] = []
688
+ }
689
+ ```
690
+
691
+ ✅ **Good: Actor for concurrent state**
692
+ ```swift
693
+ actor DatabaseManager { // ✅ Actor for thread-safe mutable state
694
+ private var cache: [UUID: User] = [:]
695
+ }
696
+ ```
697
+
698
+ ### 7.2 Copy-on-Write
699
+
700
+ **Check for:**
701
+ - [ ] Structs with large data use copy-on-write
702
+ - [ ] Custom copy-on-write for performance-critical code
703
+
704
+ **Examples:**
705
+
706
+ ✅ **Good: Copy-on-write for large data**
707
+ ```swift
708
+ struct LargeDataSet {
709
+ private var storage: Storage // ✅ Reference type storage
710
+
711
+ private final class Storage {
712
+ var data: [Int]
713
+ init(data: [Int]) { self.data = data }
714
+ }
715
+
716
+ mutating func append(_ value: Int) {
717
+ if !isKnownUniquelyReferenced(&storage) {
718
+ storage = Storage(data: storage.data) // ✅ Copy on write
719
+ }
720
+ storage.data.append(value)
721
+ }
722
+ }
723
+ ```
724
+
725
+ ---
726
+
727
+ ## 8. Property Wrappers
728
+
729
+ ### 8.1 Built-in Property Wrappers
730
+
731
+ **Check for:**
732
+ - [ ] Appropriate use of property wrappers
733
+ - [ ] No misuse or overuse
734
+
735
+ **Common Property Wrappers:**
736
+
737
+ | Property Wrapper | Use Case |
738
+ |-----------------|----------|
739
+ | `@Published` | Observable properties (with ObservableObject) |
740
+ | `@State` | View-local state (SwiftUI) |
741
+ | `@Binding` | Two-way binding (SwiftUI) |
742
+ | `@Environment` | Dependency injection (SwiftUI) |
743
+ | `@AppStorage` | UserDefaults-backed properties |
744
+ | `@MainActor` | Main thread isolation |
745
+ | `@TaskLocal` | Task-local values |
746
+
747
+ **Examples:**
748
+
749
+ ✅ **Good: Appropriate property wrapper use**
750
+ ```swift
751
+ @MainActor
752
+ final class UserViewModel: ObservableObject {
753
+ @Published var users: [User] = [] // ✅ For ObservableObject
754
+ @Published var isLoading: Bool = false
755
+ }
756
+
757
+ struct UserView: View {
758
+ @State private var selectedUser: User? // ✅ View-local state
759
+ @Environment(\.dismiss) private var dismiss // ✅ Environment
760
+ }
761
+ ```
762
+
763
+ ---
764
+
765
+ ## 9. Code Organization
766
+
767
+ ### 9.1 MARK Comments
768
+
769
+ **Check for:**
770
+ - [ ] MARK comments for logical sections
771
+ - [ ] Consistent section ordering
772
+ - [ ] Separation of protocol conformances
773
+
774
+ **Examples:**
775
+
776
+ ✅ **Good: Organized with MARK**
777
+ ```swift
778
+ final class UserViewModel {
779
+ // MARK: - Properties
780
+ private let authService: AuthService
781
+ @Published var users: [User] = []
782
+
783
+ // MARK: - Initialization
784
+ init(authService: AuthService) {
785
+ self.authService = authService
786
+ }
787
+
788
+ // MARK: - Public Methods
789
+ func fetchUsers() async {
790
+ // Implementation
791
+ }
792
+
793
+ // MARK: - Private Methods
794
+ private func parseUsers(_ data: Data) -> [User] {
795
+ // Implementation
796
+ }
797
+ }
798
+
799
+ // MARK: - Equatable
800
+ extension UserViewModel: Equatable {
801
+ static func == (lhs: UserViewModel, rhs: UserViewModel) -> Bool {
802
+ // Implementation
803
+ }
804
+ }
805
+ ```
806
+
807
+ ### 9.2 Extensions for Protocol Conformances
808
+
809
+ **Check for:**
810
+ - [ ] Protocol conformances in separate extensions
811
+ - [ ] Logical grouping of related functionality
812
+
813
+ **Examples:**
814
+
815
+ ✅ **Good: Extensions for protocols**
816
+ ```swift
817
+ struct User {
818
+ let id: UUID
819
+ let name: String
820
+ }
821
+
822
+ // MARK: - Identifiable
823
+ extension User: Identifiable { }
824
+
825
+ // MARK: - Codable
826
+ extension User: Codable { }
827
+
828
+ // MARK: - Equatable
829
+ extension User: Equatable { }
830
+
831
+ // MARK: - CustomStringConvertible
832
+ extension User: CustomStringConvertible {
833
+ var description: String {
834
+ "User(id: \(id), name: \(name))"
835
+ }
836
+ }
837
+ ```
838
+
839
+ ---
840
+
841
+ ## 10. Modern Swift Features
842
+
843
+ ### 10.1 Swift 6 Features
844
+
845
+ **Check for:**
846
+ - [ ] Use of new Swift 6 features where appropriate
847
+ - [ ] Typed throws
848
+ - [ ] Strict concurrency checking
849
+ - [ ] Noncopyable types (where applicable)
850
+
851
+ **Examples:**
852
+
853
+ ✅ **Good: Typed throws**
854
+ ```swift
855
+ func fetchUser(id: UUID) throws(NetworkError) -> User {
856
+ // Implementation
857
+ }
858
+ ```
859
+
860
+ ✅ **Good: Noncopyable types**
861
+ ```swift
862
+ struct FileHandle: ~Copyable { // ✅ Swift 6: noncopyable
863
+ private let descriptor: Int32
864
+
865
+ consuming func close() {
866
+ // Close file descriptor
867
+ }
868
+ }
869
+ ```
870
+
871
+ ### 10.2 Availability Attributes
872
+
873
+ **Check for:**
874
+ - [ ] Availability attributes for new APIs
875
+ - [ ] Backward compatibility considerations
876
+ - [ ] Feature detection for platform-specific code
877
+
878
+ **Examples:**
879
+
880
+ ✅ **Good: Availability attributes**
881
+ ```swift
882
+ @available(iOS 17.0, macOS 14.0, *)
883
+ func modernFeature() {
884
+ // Use iOS 17+ APIs
885
+ }
886
+
887
+ func compatibleFunction() {
888
+ if #available(iOS 17.0, *) {
889
+ modernFeature()
890
+ } else {
891
+ // Fallback implementation
892
+ }
893
+ }
894
+ ```
895
+
896
+ ---
897
+
898
+ ## Quick Reference Checklist
899
+
900
+ ### Critical Issues
901
+ - [ ] No data races (shared mutable state)
902
+ - [ ] No force unwraps (`!`, `as!`, `try!`)
903
+ - [ ] Proper actor isolation
904
+ - [ ] MainActor for UI code
905
+
906
+ ### High Priority
907
+ - [ ] Async/await instead of completion handlers
908
+ - [ ] Typed throws for error handling
909
+ - [ ] Sendable conformance for types crossing actors
910
+ - [ ] Explicit access control
911
+
912
+ ### Medium Priority
913
+ - [ ] Proper naming conventions
914
+ - [ ] MARK comments for organization
915
+ - [ ] Protocol conformances in extensions
916
+ - [ ] Meaningful error types
917
+
918
+ ### Low Priority
919
+ - [ ] Type inference vs explicit types
920
+ - [ ] Comments for complex logic
921
+ - [ ] Consistent code style
922
+
923
+ ---
924
+
925
+ ## Version
926
+ **Last Updated**: 2026-02-10
927
+ **Version**: 1.0.0
928
+ **Swift Version**: 6.0+