Use when touching widgets, animations, networking configuration, or background/observer cleanup — battery and performance patterns for WidgetKit timelines, SwiftUI animations, Low Power Mode handling, URLSession config, and NotificationCenter/Task cleanup under `@Observable`.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add patrickserrano/lacquer --skill ios-performance-battery-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ios Performance Battery Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/patrickserrano-ios-performance-battery-patterns)More formats (shields.io, HTML) on the badges page.
---
name: ios-performance-battery-patterns
description: >
Use when touching widgets, animations, networking configuration, or
background/observer cleanup — battery and performance patterns for
WidgetKit timelines, SwiftUI animations, Low Power Mode handling,
URLSession config, and NotificationCenter/Task cleanup under `@Observable`.
---
# Battery & Performance Patterns
Apply these whenever touching widgets, animations, networking, or background work.
## Widgets
- Limit `Timeline` entries to **≤ 2** (current + one next-day refresh). More entries run the provider repeatedly and drain battery.
- Use `.atEnd` reload policy — let WidgetKit decide when to refresh.
## Animations
- Always stop animations in `.onDisappear`. Animations left running off-screen still consume CPU/GPU.
- Bind repeating animations to a `@State var isAnimating = false`: set `true` in `.onAppear`, `false` in `.onDisappear`, and pass `value: isAnimating` to `withAnimation`.
- Use `.repeatCount(N)` instead of `.repeatForever` for attention animations.
## Low Power Mode
Guard expensive operations before they start:
```swift
guard !ProcessInfo.processInfo.isLowPowerModeEnabled else { return }
```
Apply to: image preloading, background downloads, video prefetch, heavy sync.
## Network
```swift
let config = URLSessionConfiguration.default
config.allowsConstrainedNetworkAccess = false // respect Low Data Mode
config.allowsExpensiveNetworkAccess = false // avoid cellular when Wi-Fi preferred
config.waitsForConnectivity = true // queue rather than fail when offline
```
## Observer & Task Cleanup
`@Observable` macro-generated storage prevents `nonisolated deinit` from removing `NotificationCenter` observers. Use reference-type boxes instead:
```swift
final class NotificationObserverBox {
private var tokens: [NSObjectProtocol] = []
func add(_ token: NSObjectProtocol) { tokens.append(token) }
deinit { tokens.forEach { NotificationCenter.default.removeObserver($0) } }
}
final class TaskBox {
private var cancel: (() -> Void)?
func store<Success, Failure>(_ task: Task<Success, Failure>) { cancel = { task.cancel() } }
deinit { cancel?() }
}
```
For `MPRemoteCommandCenter`: store `addTarget` return values; call `removeTarget(nil)` on each in `deinit`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!