Install
$ agentstack add skill-mwd1234-ios-agentic-skills-crash-safety ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
About
Crash & Error Resilience Audit
Find risky unwraps, missing guards, and unhandled errors. Add safe fallbacks and user-friendly error states.
When to use this skill
- Before App Store submission
- After adding new async/error-prone code
- When reviewing PRs with optional handling
- After crash reports from TestFlight
Quick Reference: Risk Levels
| Pattern | Risk | Fix | |---------|------|-----| | fatalError() | 🔴 Critical | Remove or guard with #if DEBUG | | ! force unwrap | 🔴 High | Use guard let, if let, or ?? | | try! | 🔴 High | Use do/catch or try? with fallback | | preconditionFailure() | 🔴 High | Remove from production paths | | Implicit unwrap (Type!) | 🟡 Medium | Convert to optional with safe access | | Missing @MainActor | 🟡 Medium | Add for UI-updating code |
Step 1: Fatal Crash Patterns
1.1 fatalError / preconditionFailure / assertionFailure
# These crash in production!
rg --type swift -g '!*Tests*' -g '!*UITests*' 'fatalError\(|preconditionFailure\(|assertionFailure\(' YourApp/
Fix: Remove or wrap in #if DEBUG:
#if DEBUG
fatalError("Unimplemented")
#else
return defaultValue
#endif
1.2 Force Unwraps (!)
# Force unwraps - tighter pattern to reduce false positives
rg --type swift -g '!*Tests*' -g '!*UITests*' '[a-zA-Z_][a-zA-Z0-9_]*\s*!' YourApp/ | grep -v '!=' | grep -v '//' | head -40
Exceptions (OK to skip):
@IBOutlet(UIKit pattern)NSImage(named:)!with known system imagesURL(string: "https://...")!with hardcoded valid URLs- Code inside
#Preview { }blocks - Code inside
*Tests*/directories
1.3 Force Try (try!)
rg --type swift -g '!*Tests*' -g '!*UITests*' 'try!' YourApp/
> Note: try! is acceptable in tests and previews where failure should crash during development.
Fix: Replace with do/catch or try? with default:
// ❌ Crashes on failure
let data = try! encoder.encode(object)
// ✅ Safe with error handling
let data = try? encoder.encode(object) ?? Data()
1.4 Implicitly Unwrapped Optionals (Type!)
rg --type swift -g '!*Tests*' ': [A-Z][a-zA-Z0-9_]*!' YourApp/ | grep -v '@IBOutlet' | head -20
Step 2: Optional Safety Audit
2.1 Chained Optional Access Without Guards
# Deep optional chains that may be fragile
rg --type swift -g '!*Tests*' '\?\.\w+\?\.\w+' YourApp/ | head -20
2.2 Array/Dictionary Subscript Without Bounds Check
# Direct array indexing (may crash on out-of-bounds)
rg --type swift -g '!*Tests*' '\[\d+\]|\[index\]|\[i\]' YourApp/ | head -20
Fix: Use safe subscript or bounds check:
let item = array.indices.contains(index) ? array[index] : nil
Step 3: Error Handling Audit
3.1 Empty Catch Blocks
# Swallowed errors (should at least log)
rg --type swift -g '!*Tests*' -A2 'catch\s*\{' YourApp/ | grep -B1 '^\s*\}' | head -20
3.2 Result Types Without Failure Handling
rg --type swift -g '!*Tests*' 'Result<' YourApp/ | head -15
rg --type swift -g '!*Tests*' '\.failure\(' YourApp/ | head -15
Step 4: Async/Concurrency Safety
4.1 Missing @MainActor for UI Updates
# Task blocks that may update UI
rg --type swift -g '!*Tests*' 'Task\s*\{' YourApp/Views/ | head -20
# Check for MainActor annotations
rg --type swift -g '!*Tests*' '@MainActor' YourApp/
Fix: UI-updating async code needs @MainActor:
Task { @MainActor in
self.isLoading = false
}
4.2 Task.detached & Continuation Misuse
# Task.detached (often misused, can cause actor isolation issues)
rg --type swift -g '!*Tests*' 'Task\.detached' YourApp/
# Continuations (must resume exactly once - missing resume = deadlock)
rg --type swift -g '!*Tests*' 'withCheckedContinuation|withUnsafeContinuation|withCheckedThrowingContinuation' YourApp/
Verify continuations:
- Every code path must call
continuation.resume()exactly once - Missing resume = deadlock
- Double resume = crash
4.3 Unstructured Task Cancellation
# Tasks that should be cancelled when view disappears
rg --type swift -g '!*Tests*' '\.task\s*\{|Task\s*\{' YourApp/Views/ | head -20
Verify: Long-running tasks should use .task { } modifier (auto-cancels) or manual cancellation.
Step 5: User-Facing Error States
5.1 ContentUnavailableView for Empty/Error States
rg --type swift -g '!*Tests*' 'ContentUnavailableView' YourApp/Views/
5.2 Alert for User-Facing Errors
rg --type swift -g '!*Tests*' '\.alert\(' YourApp/Views/ | head -15
Step 6: Watch App Audit
WATCH_DIR="YourApp Watch App"
# Fatal patterns in Watch app
rg --type swift 'fatalError\(|preconditionFailure\(' "$WATCH_DIR/"
# Force unwraps in Watch app
rg --type swift '[a-zA-Z_][a-zA-Z0-9_]*!' "$WATCH_DIR/" | grep -v '!=' | grep -v '//' | head -20
Skip Patterns
*Tests*/,*UITests*/— expected to crash on failure#Preview { }blocks — development only@IBOutletforce unwraps — UIKit pattern- Hardcoded valid URLs:
URL(string: "https://...")!
Output Format
| Category | Issues | Status | |----------|--------|--------| | fatalError/precondition | X | ✅/❌ | | Force unwraps (!) | X | ✅/❌ | | Force try (try!) | X | ✅/❌ | | Empty catch blocks | X | ✅/❌ | | Task.detached/continuations | X | ✅/❌ | | Missing @MainActor | X | ✅/❌ | | User error states | X | ✅/❌ | | Watch app | X | ✅/❌ |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mwd1234
- Source: mwd1234/ios-agentic-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.