AgentStack
SKILL verified MIT Self-run

Performance

skill-mwd1234-ios-agentic-skills-performance · by mwd1234

Audit for performance and battery - layout thrash, heavy animations, timers, background tasks. Identifies hotspots affecting smoothness and power consumption. Use before releases or when users report lag/battery drain.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-mwd1234-ios-agentic-skills-performance

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Performance? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Performance & Battery Audit

Scan for layout thrash, heavy animations, timers, and background tasks. Flag hotspots and suggest fixes.

When to use this skill

  • Before App Store submission
  • After adding complex animations or layouts
  • When users report lag, jank, or battery drain
  • When reviewing Views with frequent state changes

Quick Reference: Common Issues

| Issue | Impact | Fix | |-------|--------|-----| | GeometryReader in ScrollView | Layout thrash | Use containerRelativeFrame or cache sizes | | Timer in View body | Battery drain | Use .onReceive with shared timer | | Large images in List | Memory spike | Use LazyVStack, async image loading | | Animation without value: | CPU/GPU | Scope animations with value: parameter | | .drawingGroup() everywhere | GPU memory | Use only for complex overlapping content |


Step 1: Layout Performance Audit

1.1 GeometryReader Misuse

# GeometryReader (expensive layout pass)
rg --type swift -g '!*Tests*' 'GeometryReader' YourApp/Views/ | head -15

Issues: GeometryReader inside ScrollView/List causes relayout on scroll.

Fix (iOS 17+):

// ❌ Expensive
GeometryReader { geo in content.frame(width: geo.size.width * 0.8) }

// ✅ Modern alternative
content.containerRelativeFrame(.horizontal) { width, _ in width * 0.8 }

1.2 Layout Invalidation in Body

# Inline expensive object creation
rg --type swift -g '!*Tests*' 'DateFormatter\(\)|NumberFormatter\(\)|JSONDecoder\(\)' YourApp/Views/

Fix: Move to static/cached properties.


Step 2: Animation Performance

2.1 Animation Scope

# Animations without value parameter (animate everything)
rg --type swift -g '!*Tests*' '\.animation\([^,)]+\)' YourApp/Views/ | grep -v 'value:' | head -15

Fix: Always scope animations:

.animation(.easeInOut, value: isExpanded)  // ✅ Only animates this change

2.2 Heavy/Repeating Animations

# Repeating animations (battery impact)
rg --type swift -g '!*Tests*' '\.repeatForever|\.repeat\(' YourApp/Views/

# Canvas/TimelineView (GPU intensive)
rg --type swift -g '!*Tests*' 'Canvas\s*\{|TimelineView' YourApp/Views/

> watchOS: TimelineView(.periodic) is extremely battery-heavy. Prefer .animation schedule or pause when not visible.

2.3 Expensive Rendering Modifiers

# GPU-heavy modifiers
rg --type swift -g '!*Tests*' '\.drawingGroup\(|\.shadow\(radius:|\.blur\(|\.mask\s*\{|\.compositingGroup\(' YourApp/Views/ | head -20

Guidance:

  • .drawingGroup() — Use only for complex overlapping content, not everywhere
  • .shadow(radius:) — Expensive with large radii; cache or use images
  • .blur() — Very expensive; consider pre-blurred assets
  • .mask { } — Recalculates every frame; avoid in animations
  • .compositingGroup() — Use sparingly for correct blending

Step 3: ForEach & List Efficiency

3.1 Unstable ForEach IDs

# ForEach with \.self on non-Hashable-stable data (causes full diff)
rg --type swift -g '!*Tests*' 'ForEach.*\\\.self' YourApp/Views/ | head -15

# ForEach without explicit id:
rg --type swift -g '!*Tests*' 'ForEach\([^)]+\)\s*\{' YourApp/Views/ | grep -v 'id:' | head -15

Issues:

  • \.self on arrays that get reordered/modified causes full re-render
  • Missing stable IDs cause diffing cost

Fix: Use stable, unique identifiers:

ForEach(items, id: \.stableID) { item in ... }

3.2 LazyVStack/LazyHStack Usage

# Check for lazy stacks in lists
rg --type swift -g '!*Tests*' 'LazyVStack|LazyHStack|LazyVGrid|LazyHGrid' YourApp/Views/

# Non-lazy stacks in ScrollView (loads all content)
rg --type swift -g '!*Tests*' -B2 'ScrollView' YourApp/Views/ | grep -A2 'VStack\|HStack' | head -20

Step 4: State Management

4.1 @State Arrays/Dictionaries

# Large state objects in Views
rg --type swift -g '!*Tests*' '@State\s+(private\s+)?var\s+\w+:\s*\[' YourApp/Views/ | head -15

Fix: Large collections should be in ViewModel/ObservableObject, not View @State.

4.2 @StateObject Initialization

# @StateObject in body (wrong - should be in init or property)
rg --type swift -g '!*Tests*' -B3 '@StateObject' YourApp/Views/ | head -20

Fix: Initialize @StateObject in property declaration or init, never in body:

// ✅ Correct
@StateObject private var viewModel = MyViewModel()

// ❌ Wrong - recreates on every render
var body: some View {
    let vm = MyViewModel() // BAD
}

Step 5: Timer & Background Task Audit

5.1 Timer Usage

# Timer instances
rg --type swift -g '!*Tests*' 'Timer\.|Timer\.publish|Timer\.scheduledTimer' YourApp/

Issues:

  • Timers not invalidated when view disappears
  • High-frequency timers ( watchOS priority: Battery > Smoothness. TimelineView(.periodic) drains battery fast—use .animation schedule instead.

Step 8: Instruments Verification

For issues found, verify with Instruments:

  1. Time Profiler — CPU hotspots
  2. Core Animation — Frame drops, offscreen renders
  3. Allocations — Memory leaks, spikes
  4. Energy Log — Battery impact

Skip Patterns

  • *Tests*/, *UITests*/
  • #Preview { } blocks

Output Format

| Category | Issues | Status | |----------|--------|--------| | GeometryReader usage | X | ✅/❌ | | Animation scope | X | ✅/❌ | | Expensive modifiers | X | ✅/❌ | | ForEach IDs | X | ✅/❌ | | @StateObject init | X | ✅/❌ | | Timer management | X | ✅/❌ | | Watch app battery | X | ✅/❌ |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.