Green Coding — iOS
Audit an iOS app for energy efficiency, battery impact, and sustainability.
When to use
- Auditing an iOS/iPadOS/watchOS app for energy consumption
- Investigating battery drain complaints
- Reviewing Swift/SwiftUI/UIKit code for green patterns
- Measuring SCI for a mobile operation (API call, screen render, background task)
MCP tools (optional)
If the sustainable-code MCP server is configured:
| Tool |
Purpose |
sci_calculate |
Compute SCI per mobile operation |
grid_carbon_intensity |
Get grid carbon intensity for user region |
sci_compare |
Compare SCI before/after optimization |
creedengo_check |
Check Swift files for energy-wasteful patterns |
Workflow
iOS Green Audit Progress:
- [ ] Phase 1: Explore — understand architecture and energy profile
- [ ] Phase 2: Energy profiling — identify battery-draining operations
- [ ] Phase 3: Code patterns — check against Creedengo iOS rules
- [ ] Phase 4: Network efficiency — minimize data transfer
- [ ] Phase 5: Asset optimization — reduce resource footprint
- [ ] Phase 6: SCI measurement — quantify carbon per operation
- [ ] Phase 7: Report and recommendations
Phase 1 — Explore
Understand the app's architecture and energy profile:
- Language: Swift, Objective-C, or mixed?
- UI framework: SwiftUI, UIKit, or hybrid?
- Architecture: MVC, MVVM, TCA, VIPER?
- Dependencies: CocoaPods, SPM, Carthage? How many?
- Background tasks: push notifications, background fetch, location tracking?
- Network layer: URLSession, Alamofire, custom?
- Persistence: Core Data, SwiftData, Realm, SQLite, UserDefaults?
- Media: camera, video, audio processing?
- Sensors: GPS, accelerometer, Bluetooth, NFC?
Phase 2 — Energy profiling
Identify the biggest energy consumers. On iOS, the main energy drains are:
| Component |
Energy impact |
What to check |
| Location Services |
Very high |
Continuous GPS vs significant-change vs visit monitoring |
| Networking |
High |
Request frequency, payload size, background transfers |
| CPU processing |
High |
Main thread blocking, inefficient algorithms, polling loops |
| Graphics/GPU |
High |
Overdraw, off-screen rendering, animation complexity |
| Bluetooth/sensors |
Medium-high |
Polling frequency, unnecessary scans |
| Display |
Medium |
Brightness APIs, always-on content, dark mode support |
| Background tasks |
Medium |
BGTaskScheduler usage, background refresh frequency |
Measurement tools
Recommend the user profile their app using:
- Xcode Energy Gauge (Product → Profile → Energy Impact) — real-time energy score (0-20 scale) during development
- Xcode Instruments — Energy Log — detailed per-subsystem breakdown (CPU, GPU, network, location, Bluetooth)
- MetricKit — production energy metrics from real users (iOS 13+):
// Add MXMetricManagerSubscriber to receive daily energy reports
class MetricsSubscriber: NSObject, MXMetricManagerSubscriber {
func didReceive(_ payloads: [MXMetricPayload]) {
// payloads contain cumulativeCellularConditionTime,
// cumulativeWiFiConditionTime, cpuMetrics, gpuMetrics
}
}
- Xcode Organizer → Energy — aggregated energy data from App Store users
Phase 3 — Code patterns (Creedengo iOS rules)
Check Swift files against Creedengo iOS energy rules:
| Rule |
Pattern to avoid |
Green alternative |
| Location precision |
kCLLocationAccuracyBest when not needed |
Use kCLLocationAccuracyHundredMeters or CLLocationManager.significantLocationChangeMonitoringAvailable() |
| Location continuous |
startUpdatingLocation() running permanently |
Use startMonitoringSignificantLocationChanges() or requestLocation() for one-shot |
| Sensor polling |
Timer-based accelerometer/gyroscope reads |
Use CMMotionManager with appropriate updateInterval, stop when not needed |
| Idle timer |
UIApplication.shared.isIdleTimerDisabled = true |
Only disable when genuinely needed (navigation, video playback), re-enable promptly |
| Brightness override |
Setting UIScreen.main.brightness to max |
Let the system manage brightness, respect auto-brightness |
| Torch/flashlight |
AVCaptureDevice.torchMode = .on left on |
Turn off torch as soon as task completes |
| Animation overuse |
Complex UIView.animate chains, always-running CADisplayLink |
Use UIView.animate with prefers-reduced-motion check, avoid continuous animations |
| Bluetooth scanning |
centralManager.scanForPeripherals without timeout |
Set a scan timeout, stop scanning once device found |
| Background fetch |
Aggressive setMinimumBackgroundFetchInterval |
Use BGAppRefreshTaskRequest with reasonable earliest begin date |
| Large image loading |
Loading full-resolution images into memory |
Use UIImage(contentsOfFile:) with downsampling, or ImageIO for thumbnails |
Use the creedengo_check MCP tool on Swift files, or manually review against these patterns.
Additionally check for general Swift energy patterns:
- Prefer
struct over class — value types avoid heap allocation and ARC overhead
- Avoid
DispatchQueue.main.async flooding — batch UI updates
- Use
lazy var for expensive computed properties
- Prefer
async/await over completion handler chains — cleaner, avoids retain cycles
- Use
URLSession background transfers for large downloads instead of foreground requests
Phase 4 — Network efficiency
Mobile network operations are energy-expensive. Check:
| Check |
Why it matters |
| Batch API calls |
Each network transaction wakes the radio. Batch multiple requests into one |
| Compress payloads |
Use gzip/brotli. Consider Protocol Buffers or MessagePack over JSON for high-frequency APIs |
| Cache aggressively |
Use URLCache with appropriate policies. Cache images with NSCache or third-party (Kingfisher, SDWebImage) |
| Avoid polling |
Replace polling with push notifications (APNs) or WebSocket for real-time updates |
| Background transfers |
Use URLSessionConfiguration.background for non-urgent uploads/downloads — iOS batches these efficiently |
| Prefetch intelligently |
Use UITableViewDataSourcePrefetching / UICollectionViewDataSourcePrefetching — don't prefetch everything |
| Reduce image sizes |
Request appropriate resolution from server (?w=375 for phone, ?w=768 for tablet) |
| HTTP caching headers |
Ensure ETag, Last-Modified, Cache-Control are set server-side |
Phase 5 — Asset optimization
| Asset type |
Check |
Target |
| Images |
HEIC preferred over PNG/JPEG. Use Asset Catalog with device-specific variants |
Smallest format for quality needed |
| App size |
App Thinning enabled? Bitcode? On-demand resources for large assets? |
Smaller download = less energy to transfer |
| Fonts |
System fonts (SF Pro, SF Mono) preferred over custom fonts |
Zero download cost for system fonts |
| Videos |
HLS adaptive streaming? Appropriate resolution per device? |
Don't stream 4K to an iPhone SE |
| Core Data |
Batch inserts (NSBatchInsertRequest)? Proper indexing? Fetch limits? |
Reduce disk I/O and CPU |
| Launch time |
Minimize work in application(_:didFinishLaunchingWithOptions:) |
Faster launch = less energy |
Phase 6 — SCI measurement
Measure the carbon intensity of key operations:
- Choose functional units: "per API call", "per screen render", "per background sync"
- Measure wall-clock time using
CFAbsoluteTimeGetCurrent() or ContinuousClock:let clock = ContinuousClock()
let duration = try await clock.measure {
// operation to measure
}
let wallTimeMs = duration.components.seconds * 1000
+ duration.components.attoseconds / 1_000_000_000_000_000
- Get grid carbon intensity via
grid_carbon_intensity MCP tool (use user's region)
- Calculate SCI via
sci_calculate MCP tool:
wallTimeMs: measured duration
devicePowerW: ~3W (iPhone average) or ~5W (iPad)
carbonIntensity: from step 3
embodiedTotalG: ~70000 (iPhone, from Apple Environmental Report)
lifetimeHours: ~26280 (3 years typical iPhone lifecycle)
Phase 7 — Report
## iOS Green Audit: [app name]
### Energy profile
| Component | Impact | Status | Notes |
|-----------|--------|--------|-------|
| Location | high/medium/low/none | ok/warn/fail | ... |
| Networking | ... | ... | ... |
| CPU/processing | ... | ... | ... |
| Graphics/GPU | ... | ... | ... |
| Sensors | ... | ... | ... |
| Background tasks | ... | ... | ... |
### Code patterns (Creedengo iOS)
| File | Rule violated | Severity | Fix |
|------|--------------|----------|-----|
| ... | ... | high/medium/low | ... |
### SCI measurements
| Operation | SCI (mgCO2eq) | Notes |
|-----------|---------------|-------|
| ... | ... | ... |
### Top 5 Recommendations
1. [highest impact action]
2. ...
### Methodology and sources
- Formula: SCI = ((E x I) + M) / R — [GSF SCI Specification v1.0](https://sci-guide.greensoftware.foundation/) (ISO 21031:2024)
- Code rules: [Creedengo iOS](https://github.com/green-code-initiative/creedengo-ios) — green-code-initiative
- Energy profiling: Xcode Instruments Energy Log / MetricKit
- Device power: [value] W — Apple Product Environmental Report [year]
- Embodied carbon: [value] gCO2eq — [Apple Product Environmental Report](https://www.apple.com/environment/) [year]
- Grid carbon intensity: [value] gCO2eq/kWh — [Ember Global Electricity Review](https://ember-energy.org/) [year]
- Platform guide: [Apple Energy Efficiency Guide for iOS Apps](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/)
Gotchas
- Xcode Energy Gauge is not available in simulators: Energy profiling requires a physical device. Always test energy on real hardware, not the iOS Simulator.
- MetricKit reports are daily aggregates: You cannot get real-time energy data from MetricKit. For granular measurement during development, use Xcode Instruments instead.
- Battery percentage is not a valid energy metric: Battery drain depends on total capacity, charge cycles, ambient temperature, and other apps. Use Xcode's energy score (0-20) or MetricKit cumulative metrics instead.
- Background app refresh varies by user settings: Users can disable background refresh per-app. Don't assume your background tasks always run — and don't over-schedule as backup.
Post-report verification
After presenting the iOS audit report, automatically run /gc-verify in quick mode. This triggers a Chain-of-Verification (CoVe) process: extract claims from the report, generate adversarial questions, answer each independently, and present findings under a ## Verification (CoVe) heading.
Related commands
/gc-mobile-android — green coding audit for Android apps
/gc-setup — full 9-phase sustainability audit (web-focused)
/gc-measure-sci — measure SCI for any operation
/gc-dev — daily development companion
Source: fullo/sustainable-code-skill-setup — distributed by TomeVault.
1---2name: fullo-sustainable-code-skill-setup-gc-mobile-ios3description: Green Coding — iOS4---56# Green Coding — iOS78Audit an iOS app for energy efficiency, battery impact, and sustainability.910## When to use1112- Auditing an iOS/iPadOS/watchOS app for energy consumption13- Investigating battery drain complaints14- Reviewing Swift/SwiftUI/UIKit code for green patterns15- Measuring SCI for a mobile operation (API call, screen render, background task)1617## MCP tools (optional)1819If the `sustainable-code` MCP server is configured:2021| Tool | Purpose |22|------|---------|23| `sci_calculate` | Compute SCI per mobile operation |24| `grid_carbon_intensity` | Get grid carbon intensity for user region |25| `sci_compare` | Compare SCI before/after optimization |26| `creedengo_check` | Check Swift files for energy-wasteful patterns |2728## Workflow2930```31iOS Green Audit Progress:32- [ ] Phase 1: Explore — understand architecture and energy profile33- [ ] Phase 2: Energy profiling — identify battery-draining operations34- [ ] Phase 3: Code patterns — check against Creedengo iOS rules35- [ ] Phase 4: Network efficiency — minimize data transfer36- [ ] Phase 5: Asset optimization — reduce resource footprint37- [ ] Phase 6: SCI measurement — quantify carbon per operation38- [ ] Phase 7: Report and recommendations39```4041## Phase 1 — Explore4243Understand the app's architecture and energy profile:4445- Language: Swift, Objective-C, or mixed?46- UI framework: SwiftUI, UIKit, or hybrid?47- Architecture: MVC, MVVM, TCA, VIPER?48- Dependencies: CocoaPods, SPM, Carthage? How many?49- Background tasks: push notifications, background fetch, location tracking?50- Network layer: URLSession, Alamofire, custom?51- Persistence: Core Data, SwiftData, Realm, SQLite, UserDefaults?52- Media: camera, video, audio processing?53- Sensors: GPS, accelerometer, Bluetooth, NFC?5455## Phase 2 — Energy profiling5657Identify the biggest energy consumers. On iOS, the main energy drains are:5859| Component | Energy impact | What to check |60|-----------|--------------|---------------|61| **Location Services** | Very high | Continuous GPS vs significant-change vs visit monitoring |62| **Networking** | High | Request frequency, payload size, background transfers |63| **CPU processing** | High | Main thread blocking, inefficient algorithms, polling loops |64| **Graphics/GPU** | High | Overdraw, off-screen rendering, animation complexity |65| **Bluetooth/sensors** | Medium-high | Polling frequency, unnecessary scans |66| **Display** | Medium | Brightness APIs, always-on content, dark mode support |67| **Background tasks** | Medium | BGTaskScheduler usage, background refresh frequency |6869### Measurement tools7071Recommend the user profile their app using:72731. **Xcode Energy Gauge** (Product → Profile → Energy Impact) — real-time energy score (0-20 scale) during development742. **Xcode Instruments — Energy Log** — detailed per-subsystem breakdown (CPU, GPU, network, location, Bluetooth)753. **MetricKit** — production energy metrics from real users (iOS 13+):76 ```swift77 // Add MXMetricManagerSubscriber to receive daily energy reports78 class MetricsSubscriber: NSObject, MXMetricManagerSubscriber {79 func didReceive(_ payloads: [MXMetricPayload]) {80 // payloads contain cumulativeCellularConditionTime,81 // cumulativeWiFiConditionTime, cpuMetrics, gpuMetrics82 }83 }84 ```854. **Xcode Organizer → Energy** — aggregated energy data from App Store users8687## Phase 3 — Code patterns (Creedengo iOS rules)8889Check Swift files against [Creedengo iOS](https://github.com/green-code-initiative/creedengo-ios) energy rules:9091| Rule | Pattern to avoid | Green alternative |92|------|-----------------|-------------------|93| **Location precision** | `kCLLocationAccuracyBest` when not needed | Use `kCLLocationAccuracyHundredMeters` or `CLLocationManager.significantLocationChangeMonitoringAvailable()` |94| **Location continuous** | `startUpdatingLocation()` running permanently | Use `startMonitoringSignificantLocationChanges()` or `requestLocation()` for one-shot |95| **Sensor polling** | Timer-based accelerometer/gyroscope reads | Use `CMMotionManager` with appropriate `updateInterval`, stop when not needed |96| **Idle timer** | `UIApplication.shared.isIdleTimerDisabled = true` | Only disable when genuinely needed (navigation, video playback), re-enable promptly |97| **Brightness override** | Setting `UIScreen.main.brightness` to max | Let the system manage brightness, respect auto-brightness |98| **Torch/flashlight** | `AVCaptureDevice.torchMode = .on` left on | Turn off torch as soon as task completes |99| **Animation overuse** | Complex `UIView.animate` chains, always-running CADisplayLink | Use `UIView.animate` with `prefers-reduced-motion` check, avoid continuous animations |100| **Bluetooth scanning** | `centralManager.scanForPeripherals` without timeout | Set a scan timeout, stop scanning once device found |101| **Background fetch** | Aggressive `setMinimumBackgroundFetchInterval` | Use `BGAppRefreshTaskRequest` with reasonable earliest begin date |102| **Large image loading** | Loading full-resolution images into memory | Use `UIImage(contentsOfFile:)` with downsampling, or `ImageIO` for thumbnails |103104Use the `creedengo_check` MCP tool on Swift files, or manually review against these patterns.105106Additionally check for general Swift energy patterns:107108- **Prefer `struct` over `class`** — value types avoid heap allocation and ARC overhead109- **Avoid `DispatchQueue.main.async` flooding** — batch UI updates110- **Use `lazy var`** for expensive computed properties111- **Prefer `async/await`** over completion handler chains — cleaner, avoids retain cycles112- **Use `URLSession` background transfers** for large downloads instead of foreground requests113114## Phase 4 — Network efficiency115116Mobile network operations are energy-expensive. Check:117118| Check | Why it matters |119|-------|---------------|120| **Batch API calls** | Each network transaction wakes the radio. Batch multiple requests into one |121| **Compress payloads** | Use gzip/brotli. Consider Protocol Buffers or MessagePack over JSON for high-frequency APIs |122| **Cache aggressively** | Use `URLCache` with appropriate policies. Cache images with `NSCache` or third-party (Kingfisher, SDWebImage) |123| **Avoid polling** | Replace polling with push notifications (APNs) or WebSocket for real-time updates |124| **Background transfers** | Use `URLSessionConfiguration.background` for non-urgent uploads/downloads — iOS batches these efficiently |125| **Prefetch intelligently** | Use `UITableViewDataSourcePrefetching` / `UICollectionViewDataSourcePrefetching` — don't prefetch everything |126| **Reduce image sizes** | Request appropriate resolution from server (`?w=375` for phone, `?w=768` for tablet) |127| **HTTP caching headers** | Ensure `ETag`, `Last-Modified`, `Cache-Control` are set server-side |128129## Phase 5 — Asset optimization130131| Asset type | Check | Target |132|------------|-------|--------|133| **Images** | HEIC preferred over PNG/JPEG. Use Asset Catalog with device-specific variants | Smallest format for quality needed |134| **App size** | App Thinning enabled? Bitcode? On-demand resources for large assets? | Smaller download = less energy to transfer |135| **Fonts** | System fonts (SF Pro, SF Mono) preferred over custom fonts | Zero download cost for system fonts |136| **Videos** | HLS adaptive streaming? Appropriate resolution per device? | Don't stream 4K to an iPhone SE |137| **Core Data** | Batch inserts (`NSBatchInsertRequest`)? Proper indexing? Fetch limits? | Reduce disk I/O and CPU |138| **Launch time** | Minimize work in `application(_:didFinishLaunchingWithOptions:)` | Faster launch = less energy |139140## Phase 6 — SCI measurement141142Measure the carbon intensity of key operations:1431441. **Choose functional units**: "per API call", "per screen render", "per background sync"1452. **Measure wall-clock time** using `CFAbsoluteTimeGetCurrent()` or `ContinuousClock`:146 ```swift147 let clock = ContinuousClock()148 let duration = try await clock.measure {149 // operation to measure150 }151 let wallTimeMs = duration.components.seconds * 1000152 + duration.components.attoseconds / 1_000_000_000_000_000153 ```1543. **Get grid carbon intensity** via `grid_carbon_intensity` MCP tool (use user's region)1554. **Calculate SCI** via `sci_calculate` MCP tool:156 - `wallTimeMs`: measured duration157 - `devicePowerW`: ~3W (iPhone average) or ~5W (iPad)158 - `carbonIntensity`: from step 3159 - `embodiedTotalG`: ~70000 (iPhone, from Apple Environmental Report)160 - `lifetimeHours`: ~26280 (3 years typical iPhone lifecycle)161162## Phase 7 — Report163164```165## iOS Green Audit: [app name]166167### Energy profile168| Component | Impact | Status | Notes |169|-----------|--------|--------|-------|170| Location | high/medium/low/none | ok/warn/fail | ... |171| Networking | ... | ... | ... |172| CPU/processing | ... | ... | ... |173| Graphics/GPU | ... | ... | ... |174| Sensors | ... | ... | ... |175| Background tasks | ... | ... | ... |176177### Code patterns (Creedengo iOS)178| File | Rule violated | Severity | Fix |179|------|--------------|----------|-----|180| ... | ... | high/medium/low | ... |181182### SCI measurements183| Operation | SCI (mgCO2eq) | Notes |184|-----------|---------------|-------|185| ... | ... | ... |186187### Top 5 Recommendations1881. [highest impact action]1892. ...190191### Methodology and sources192- Formula: SCI = ((E x I) + M) / R — [GSF SCI Specification v1.0](https://sci-guide.greensoftware.foundation/) (ISO 21031:2024)193- Code rules: [Creedengo iOS](https://github.com/green-code-initiative/creedengo-ios) — green-code-initiative194- Energy profiling: Xcode Instruments Energy Log / MetricKit195- Device power: [value] W — Apple Product Environmental Report [year]196- Embodied carbon: [value] gCO2eq — [Apple Product Environmental Report](https://www.apple.com/environment/) [year]197- Grid carbon intensity: [value] gCO2eq/kWh — [Ember Global Electricity Review](https://ember-energy.org/) [year]198- Platform guide: [Apple Energy Efficiency Guide for iOS Apps](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/EnergyGuide-iOS/)199```200201## Gotchas202203- **Xcode Energy Gauge is not available in simulators**: Energy profiling requires a physical device. Always test energy on real hardware, not the iOS Simulator.204- **MetricKit reports are daily aggregates**: You cannot get real-time energy data from MetricKit. For granular measurement during development, use Xcode Instruments instead.205- **Battery percentage is not a valid energy metric**: Battery drain depends on total capacity, charge cycles, ambient temperature, and other apps. Use Xcode's energy score (0-20) or MetricKit cumulative metrics instead.206- **Background app refresh varies by user settings**: Users can disable background refresh per-app. Don't assume your background tasks always run — and don't over-schedule as backup.207208## Post-report verification209210After presenting the iOS audit report, automatically run `/gc-verify` in quick mode. This triggers a Chain-of-Verification (CoVe) process: extract claims from the report, generate adversarial questions, answer each independently, and present findings under a `## Verification (CoVe)` heading.211212## Related commands213214- `/gc-mobile-android` — green coding audit for Android apps215- `/gc-setup` — full 9-phase sustainability audit (web-focused)216- `/gc-measure-sci` — measure SCI for any operation217- `/gc-dev` — daily development companion218219---220> Source: [fullo/sustainable-code-skill-setup](https://github.com/fullo/sustainable-code-skill-setup) — distributed by [TomeVault](https://tomevault.io).221<!-- tomevault:4.0:skill_md:2026-06-16 -->