Signed-off-by: Matt Bruce <matt.bruce1@toyota.com>
This commit is contained in:
parent
88e4402d38
commit
f3dd8d92bd
@ -8,13 +8,9 @@ globs: ["**/*.swift", "**/*.xcstrings"]
|
||||
|
||||
Use **String Catalogs** (`.xcstrings` files) for localization in modern Swift projects.
|
||||
|
||||
## Required Language Support
|
||||
## Language Support
|
||||
|
||||
At minimum, support these languages:
|
||||
|
||||
- **English (en)** - Base language
|
||||
- **Spanish - Mexico (es-MX)**
|
||||
- **French - Canada (fr-CA)**
|
||||
At minimum, support the base development language (typically English). Add additional locales based on your app's target markets. Common additions include Spanish and French variants.
|
||||
|
||||
## How String Catalogs Work
|
||||
|
||||
|
||||
@ -261,7 +261,9 @@ let result = largeArray
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Prefer Typed Throws (Swift 6)
|
||||
### Prefer Typed Throws (Swift 6 / Xcode 16+)
|
||||
|
||||
Typed throws requires the **Swift 6 compiler** (shipped with Xcode 16). The feature works at any deployment target, but your project must compile with Swift 6. If your team hasn't migrated yet, continue using untyped `throws`.
|
||||
|
||||
```swift
|
||||
// Swift 6 - Typed throws
|
||||
|
||||
@ -45,10 +45,7 @@ Each protocol should represent one capability (Interface Segregation Principle):
|
||||
|
||||
```swift
|
||||
// GOOD - Focused protocols
|
||||
protocol Identifiable {
|
||||
var id: UUID { get }
|
||||
}
|
||||
|
||||
// Note: Swift provides Identifiable already — adopt it, don't redefine it.
|
||||
protocol Nameable {
|
||||
var displayName: String { get }
|
||||
}
|
||||
@ -58,8 +55,13 @@ protocol Timestamped {
|
||||
var updatedAt: Date { get }
|
||||
}
|
||||
|
||||
// Compose as needed
|
||||
struct User: Identifiable, Nameable, Timestamped { ... }
|
||||
// Compose as needed (Identifiable comes from Swift standard library)
|
||||
struct User: Identifiable, Nameable, Timestamped {
|
||||
let id: UUID
|
||||
var displayName: String
|
||||
var createdAt: Date
|
||||
var updatedAt: Date
|
||||
}
|
||||
```
|
||||
|
||||
```swift
|
||||
|
||||
@ -99,34 +99,6 @@ final class NavigationStore {
|
||||
}
|
||||
```
|
||||
|
||||
## Tab View
|
||||
|
||||
### Use Tab API Not tabItem()
|
||||
|
||||
```swift
|
||||
// BAD - Old tabItem pattern
|
||||
TabView {
|
||||
HomeView()
|
||||
.tabItem {
|
||||
Label("Home", systemImage: "house")
|
||||
}
|
||||
SettingsView()
|
||||
.tabItem {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD - Tab API (iOS 18+)
|
||||
TabView {
|
||||
Tab("Home", systemImage: "house") {
|
||||
HomeView()
|
||||
}
|
||||
Tab("Settings", systemImage: "gear") {
|
||||
SettingsView()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Observable Pattern
|
||||
|
||||
### Use @Observable Not ObservableObject
|
||||
@ -294,24 +266,32 @@ func makeView(for type: ViewType) -> some View {
|
||||
|
||||
## Lists and ForEach
|
||||
|
||||
### Don't Convert to Array for Enumeration
|
||||
### Use Identifiable Conformance for ForEach
|
||||
|
||||
Let `ForEach` use `Identifiable` conformance directly — don't bypass it with manual key paths or offset-based identity.
|
||||
|
||||
```swift
|
||||
// BAD - Unnecessary Array conversion
|
||||
// BAD - offset-based id breaks animations when items change
|
||||
ForEach(Array(items.enumerated()), id: \.offset) { index, item in
|
||||
// ...
|
||||
}
|
||||
|
||||
// GOOD - Use indices or zip
|
||||
// BAD - index-based id has the same animation problem
|
||||
ForEach(items.indices, id: \.self) { index in
|
||||
let item = items[index]
|
||||
// ...
|
||||
}
|
||||
|
||||
// GOOD - If you need both
|
||||
ForEach(Array(zip(items.indices, items)), id: \.0) { index, item in
|
||||
// GOOD - Identifiable items work directly (protocol-based)
|
||||
ForEach(items) { item in
|
||||
// ...
|
||||
}
|
||||
|
||||
// GOOD - When index is also needed, use enumerated keyed on the item's identity
|
||||
ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
|
||||
// Stable identity comes from item.id (Identifiable conformance),
|
||||
// not from the offset — so animations and diffing work correctly.
|
||||
}
|
||||
```
|
||||
|
||||
### Hide Scroll Indicators
|
||||
|
||||
Loading…
Reference in New Issue
Block a user