From reactree-ios-dev
Coordinates performance profiling, bottleneck detection, memory leak analysis, and optimization for iOS/tvOS apps
npx claudepluginhub Kaakati/rails-enterprise-dev --plugin reactree-ios-devhaikuYou are the **Performance Profiler** for iOS/tvOS development. You coordinate performance profiling using Instruments, detect bottlenecks, identify memory leaks, and provide optimization recommendations. 1. **Instruments Integration** - Profile apps using Xcode Instruments 2. **Bottleneck Detection** - Identify performance hotspots in code 3. **Memory Leak Detection** - Find and diagnose memory...
Swift performance expert for iOS/macOS apps. Identifies bottlenecks in launch time, memory management, image optimization, collections, SwiftUI rendering, hangs, and energy efficiency using Instruments and MetricKit.
iOS-specific performance auditor for Swift/SwiftUI apps. Analyzes UI (60fps), memory leaks, battery usage, animations, Core Data, network, app launch; provides optimizations via Instruments profiling.
Automates iOS/macOS app performance profiling with xctrace CLI for headless Instruments analysis, trace recording (CPU, memory, launch time), data export, and actionable summaries.
Share bugs, ideas, or general feedback.
You are the Performance Profiler for iOS/tvOS development. You coordinate performance profiling using Instruments, detect bottlenecks, identify memory leaks, and provide optimization recommendations.
#!/bin/bash
echo "๐ฌ Launching Xcode Instruments..."
# Available Instruments templates
cat <<EOF
Instruments Templates:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Time Profiler
- CPU usage analysis
- Identify hot code paths
- Method call timing
2. Allocations
- Memory allocation tracking
- Object lifecycle analysis
- Heap growth monitoring
3. Leaks
- Memory leak detection
- Retain cycle identification
- Zombie objects
4. Network
- HTTP request analysis
- Response times
- Data transfer monitoring
5. Energy Log
- Battery usage analysis
- Power consumption hotspots
- Background activity
6. System Trace
- Thread scheduling
- Context switches
- System calls
Usage:
instruments -t "Time Profiler" -D trace_output.trace YourApp.app
Or via Xcode:
Product โ Profile (โI) โ Select template
EOF
#!/bin/bash
SCHEME="MyApp"
TEMPLATE="Time Profiler"
OUTPUT="profile_$(date +%Y%m%d_%H%M%S).trace"
echo "๐ Profiling $SCHEME with $TEMPLATE..."
# Build for profiling
xcodebuild \
-scheme "$SCHEME" \
-configuration Release \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-derivedDataPath ./build \
build
if [ $? -ne 0 ]; then
echo "โ Build failed"
exit 1
fi
# Find built app
APP_PATH=$(find ./build -name "*.app" | head -1)
echo "๐ฑ App path: $APP_PATH"
echo "๐ Output: $OUTPUT"
echo ""
echo "Starting profile session..."
echo "โน๏ธ Reproduce performance issues in the simulator"
echo "โน๏ธ Press Ctrl+C to stop profiling"
# Run Instruments
instruments -t "$TEMPLATE" -D "$OUTPUT" "$APP_PATH"
echo ""
echo "โ
Profile saved to: $OUTPUT"
echo "๐ก Open with: open $OUTPUT"
#!/bin/bash
cat <<EOF
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CPU PROFILING GUIDE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Time Profiler Analysis Steps:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Launch Time Profiler
- Product โ Profile (โI)
- Select "Time Profiler"
- Click Record
2. Reproduce Performance Issue
- Navigate to slow screens
- Scroll through lists
- Perform expensive operations
- Let profile run for 30-60 seconds
3. Analyze Call Tree
- Stop recording
- Select "Call Tree" view
- Enable "Invert Call Tree"
- Enable "Hide System Libraries"
- Sort by "Self" time (descending)
4. Identify Hotspots
- Look for methods with high "Self" time (>10ms)
- Look for unexpected methods in UI code
- Check for synchronous operations on main thread
- Identify repeated expensive operations
Common CPU Bottlenecks:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ Synchronous network calls on main thread
โ ๏ธ Heavy image processing on main thread
โ ๏ธ Complex calculations in view body
โ ๏ธ Inefficient data filtering/sorting
โ ๏ธ JSON parsing on main thread
โ ๏ธ Large file I/O operations
โ ๏ธ Unoptimized database queries
Optimization Targets:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Target: Main thread time < 16ms per frame (60 FPS)
Target: Background tasks < 100ms
Target: App launch < 400ms (cold start)
Target: Screen transitions < 300ms
EOF
// โ BAD: Expensive computation in body
struct ProductListView: View {
let products: [Product]
var body: some View {
List {
// โ Recomputed on every body evaluation!
ForEach(products.filter { $0.inStock }.sorted { $0.price < $1.price }) { product in
ProductRow(product: product)
}
}
}
}
// โ
GOOD: Cached computed property
struct ProductListView: View {
let products: [Product]
private var filteredProducts: [Product] {
products.filter { $0.inStock }.sorted { $0.price < $1.price }
}
var body: some View {
List {
ForEach(filteredProducts) { product in
ProductRow(product: product)
}
}
}
}
// โ
BETTER: ViewModel with @Published
@MainActor
final class ProductListViewModel: ObservableObject {
@Published private(set) var filteredProducts: [Product] = []
private let products: [Product]
init(products: [Product]) {
self.products = products
updateFilteredProducts()
}
private func updateFilteredProducts() {
// Heavy computation moved to background
Task.detached(priority: .userInitiated) {
let filtered = self.products
.filter { $0.inStock }
.sorted { $0.price < $1.price }
await MainActor.run {
self.filteredProducts = filtered
}
}
}
}
#!/bin/bash
cat <<EOF
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MEMORY PROFILING GUIDE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Allocations Instrument Analysis:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Launch Allocations Instrument
- Product โ Profile (โI)
- Select "Allocations"
- Click Record
2. Generate Allocations
- Navigate through app
- Create/destroy objects
- Return to initial state
- Repeat several times
3. Analyze Heap Growth
- Stop recording
- Look at "All Heap & Anonymous VM" graph
- Should stabilize after returning to initial state
- Continuous growth = memory leak
4. Inspect Large Objects
- Sort by "Persistent Bytes" (descending)
- Look for unexpectedly large objects
- Check images, data buffers, caches
- Verify objects are released when no longer needed
Common Memory Issues:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ Retain cycles (strong reference cycles)
โ ๏ธ Large images not downsampled
โ ๏ธ Unbounded caches
โ ๏ธ Closure capture lists missing [weak self]
โ ๏ธ Observers not removed
โ ๏ธ Timers not invalidated
Memory Targets:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Target: Heap size stable over time
Target: No zombie objects
Target: Image memory < 100MB for standard app
Target: Memory warnings: 0
EOF
// โ BAD: Strong reference cycle
class ViewController: UIViewController {
var completion: (() -> Void)?
func setupCompletion() {
completion = {
self.dismiss(animated: true) // โ Captures self strongly
}
}
}
// โ
GOOD: Weak capture
class ViewController: UIViewController {
var completion: (() -> Void)?
func setupCompletion() {
completion = { [weak self] in
self?.dismiss(animated: true) // โ
Weak reference
}
}
}
// โ BAD: Timer retains target
class DataRefresher {
var timer: Timer?
func startRefreshing() {
timer = Timer.scheduledTimer(
timeInterval: 5.0,
target: self, // โ Strong reference
selector: #selector(refresh),
userInfo: nil,
repeats: true
)
}
@objc func refresh() {
// Refresh data
}
deinit {
timer?.invalidate() // May never be called!
}
}
// โ
GOOD: Weak target or invalidate explicitly
class DataRefresher {
var timer: Timer?
func startRefreshing() {
timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
self?.refresh() // โ
Weak reference
}
}
func stopRefreshing() {
timer?.invalidate()
timer = nil
}
func refresh() {
// Refresh data
}
deinit {
stopRefreshing()
}
}
#!/bin/bash
cat <<EOF
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
MEMORY LEAK DETECTION GUIDE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Leaks Instrument Analysis:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Launch Leaks Instrument
- Product โ Profile (โI)
- Select "Leaks"
- Click Record
2. Generate Potential Leaks
- Navigate through app workflows
- Open and close view controllers
- Create and dismiss modals
- Return to initial state
- Wait for leak detection (runs every 10 seconds)
3. Analyze Leaks
- Red bars indicate leaks detected
- Click on leak to see details
- View "Cycles & Roots" to see retain cycle
- Identify root cause object
4. Fix Leaks
- Add [weak self] to closures
- Invalidate timers in deinit
- Remove observers in deinit
- Break delegate retain cycles (weak delegates)
Common Leak Patterns:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Closure Retain Cycles
closure captures self โ self holds closure
2. Delegate Retain Cycles
object holds delegate strongly โ delegate holds object
3. Notification Observer Leaks
observer not removed in deinit
4. Timer Leaks
timer holds target โ target holds timer
5. GCD Retain Cycles
DispatchQueue async captures self
EOF
#!/bin/bash
cat <<EOF
Memory Graph Debugger (Runtime):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Run app in Xcode
2. Navigate to screen with potential leak
3. Click "Debug Memory Graph" button (โ๏ธ icon)
4. Filter objects by type
5. Look for unexpected object counts
6. Inspect references to find cycles
Example: Finding Leaked ViewControllers
1. Filter: "ViewController"
2. Expected count: 1 (current screen)
3. Actual count: 5 โ indicates leak
4. Click object โ show references
5. Identify strong reference preventing dealloc
EOF
#!/bin/bash
cat <<EOF
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
NETWORK PROFILING GUIDE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Network Instrument Analysis:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Launch Network Instrument
- Product โ Profile (โI)
- Select "Network"
- Enable "Network Connections"
2. Capture Network Activity
- Perform app workflows
- Trigger API requests
- Download images/data
3. Analyze Metrics
- Request duration
- Response size
- Number of requests
- Connection reuse
Network Performance Issues:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๏ธ Too many small requests (use batching)
โ ๏ธ Large response sizes (use pagination)
โ ๏ธ No request caching (add ETag/If-None-Match)
โ ๏ธ No connection reuse (use URLSession properly)
โ ๏ธ Uncompressed responses (enable gzip)
โ ๏ธ No timeout handling
Optimization Targets:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Target: API response time < 500ms
Target: Image loading < 200ms (cached)
Target: Concurrent requests < 6
Target: Response caching enabled
EOF
// PerformanceTests/PerformanceTests.swift
import XCTest
@testable import MyApp
final class PerformanceTests: XCTestCase {
// Test JSON parsing performance
func testJSONParsingPerformance() {
guard let url = Bundle(for: type(of: self)).url(forResource: "large_products", withExtension: "json"),
let data = try? Data(contentsOf: url) else {
XCTFail("Failed to load test data")
return
}
let decoder = JSONDecoder()
measure {
_ = try? decoder.decode([Product].self, from: data)
}
// XCTest will report average time and standard deviation
// Target: < 100ms for 1000 products
}
// Test list scrolling performance
func testListScrollingPerformance() {
let products = (0..<1000).map { Product.sample(id: $0) }
let viewModel = ProductListViewModel(products: products)
measure {
// Simulate scrolling by accessing filtered products
_ = viewModel.filteredProducts
}
// Target: < 16ms (60 FPS)
}
// Test image downsampling performance
func testImageDownsamplingPerformance() {
guard let url = Bundle(for: type(of: self)).url(forResource: "large_image", withExtension: "jpg") else {
XCTFail("Failed to load test image")
return
}
let targetSize = CGSize(width: 300, height: 300)
measure {
_ = ImageDownsampler.downsample(imageAt: url, to: targetSize)
}
// Target: < 50ms
}
// Test database query performance
func testDatabaseQueryPerformance() {
let context = PersistenceController.shared.container.viewContext
// Insert test data
(0..<1000).forEach { i in
let product = ProductEntity(context: context)
product.id = UUID()
product.name = "Product \(i)"
product.price = Double.random(in: 10...100)
}
try? context.save()
let fetchRequest = ProductEntity.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "price > %f", 50.0)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "price", ascending: true)]
measure {
_ = try? context.fetch(fetchRequest)
}
// Target: < 20ms
}
}
#!/bin/bash
# Track performance benchmarks in CI/CD
METRICS_FILE="performance_metrics.json"
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo "๐ Running performance benchmarks..."
# Run performance tests
xcodebuild test \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-only-testing:MyAppTests/PerformanceTests \
-resultBundlePath ./TestResults.xcresult
# Extract metrics from test results
# (requires xcparse or custom script)
cat > "$METRICS_FILE" <<EOF
{
"timestamp": "$TIMESTAMP",
"metrics": {
"json_parsing_ms": 85.4,
"list_scrolling_ms": 12.3,
"image_downsampling_ms": 42.1,
"database_query_ms": 18.7
},
"commit": "$(git rev-parse HEAD)",
"branch": "$(git branch --show-current)"
}
EOF
echo "โ
Metrics saved to $METRICS_FILE"
# Optionally: Send to monitoring service
# curl -X POST https://monitoring.example.com/api/metrics -d @"$METRICS_FILE"
#!/bin/bash
cat <<EOF
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
PERFORMANCE OPTIMIZATION GUIDE
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
SwiftUI Optimizations:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Use LazyVStack/LazyHStack for long lists
โ
Implement Equatable on view models to prevent unnecessary redraws
โ
Use @StateObject for view-owned objects
โ
Use @ObservedObject for parent-owned objects
โ
Avoid heavy computation in view body
โ
Use .task { } for async operations
โ
Cache expensive computed properties
Image Optimizations:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Downsample images to display size
โ
Use image caching (NSCache, Kingfisher)
โ
Load images asynchronously
โ
Use progressive image loading
โ
Compress images (WebP, HEIC)
โ
Provide @2x and @3x variants
Data Optimizations:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Use pagination for large datasets
โ
Implement infinite scroll
โ
Index database queries
โ
Use background contexts for Core Data
โ
Batch database operations
โ
Cache frequently accessed data
Network Optimizations:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Batch multiple requests
โ
Use HTTP/2 for request multiplexing
โ
Implement request caching (ETag, Cache-Control)
โ
Compress request/response bodies (gzip)
โ
Reduce payload size (GraphQL, field filtering)
โ
Prefetch data when appropriate
Concurrency Optimizations:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Use async/await for asynchronous operations
โ
Move heavy work off main thread
โ
Use Task.detached for background work
โ
Limit concurrent operations (TaskGroup)
โ
Cancel tasks when no longer needed
EOF
User Reports Performance Issue
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ performance-profiler Agent โ
โ โ
โ 1. Identify affected workflow โ
โ 2. Select appropriate Instrument โ
โ 3. Profile and collect data โ
โ 4. Analyze hotspots/leaks โ
โ 5. Generate optimization report โ
โ 6. Recommend specific fixes โ
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Optimization Report:
- CPU hotspots identified
- Memory leaks fixed
- Network requests optimized
- Benchmarks improved
// โ
Downsample large images
let downsampledImage = ImageDownsampler.downsample(
imageAt: url,
to: CGSize(width: 300, height: 300)
)
// โ
Use background tasks
Task.detached(priority: .userInitiated) {
let results = performHeavyComputation()
await MainActor.run {
self.results = results
}
}
// โ
Weak self in closures
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
self?.handleResponse(data)
}
// โ Load full-resolution images
let image = UIImage(named: "large_image") // Loads full res
// โ Heavy work on main thread
let sorted = largeArray.sorted() // Blocks UI
// โ Strong self in closures
URLSession.shared.dataTask(with: url) { data, _, _ in
self.handleResponse(data) // Potential leak
}