All posts

Swift Performance Monitoring Best Practices

Monitor Swift application performance with Instruments profiling, memory tracking, network performance, and real-time crash reporting.

Swift Performance Monitoring Best Practices

Swift applications need performance monitoring to ensure smooth user experiences on iOS, macOS, and server-side deployments.

Use signposts for Custom Instrumentation

import os

let logger = Logger(subsystem: "com.app", category: "performance")
let signposter = OSSignposter(logger: logger)

func loadDashboard() async throws -> DashboardData {
    let state = signposter.beginInterval("loadDashboard")
    defer { signposter.endInterval("loadDashboard", state) }

    async let profile = fetchProfile()
    async let stats = fetchStats()
    async let notifications = fetchNotifications()

    return try await DashboardData(
        profile: profile,
        stats: stats,
        notifications: notifications
    )
}

View signpost data in Instruments' Points of Interest timeline.

Track Memory Usage

func reportMemoryUsage() {
    var info = mach_task_basic_info()
    var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size) / 4

    let result = withUnsafeMutablePointer(to: &info) {
        $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
            task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
        }
    }

    if result == KERN_SUCCESS {
        let usedMB = Double(info.resident_size) / 1024.0 / 1024.0
        logger.info("Memory usage: \(usedMB, format: .fixed(precision: 1))MB")
    }
}

Network Performance

class NetworkMonitor: NSObject, URLSessionTaskDelegate {
    func urlSession(_ session: URLSession, task: URLSessionTask,
                    didFinishCollecting metrics: URLSessionTaskMetrics) {
        for metric in metrics.transactionMetrics {
            let dns = metric.domainLookupEndDate?.timeIntervalSince(
                metric.domainLookupStartDate ?? Date()) ?? 0
            let connect = metric.connectEndDate?.timeIntervalSince(
                metric.connectStartDate ?? Date()) ?? 0
            let response = metric.responseEndDate?.timeIntervalSince(
                metric.requestStartDate ?? Date()) ?? 0

            logger.info("Network: dns=\(dns)s connect=\(connect)s total=\(response)s")
        }
    }
}

Key Metrics

  • App launch time — cold and warm starts
  • Frame drops — CADisplayLink monitoring for jank
  • Memory warnings — track didReceiveMemoryWarning frequency
  • Network latency — per-endpoint timing
  • Disk I/O — large reads/writes block the main thread

Crash and Error Monitoring

Integrate Bugsly to capture crashes, hangs, and non-fatal errors in production. Swift's crash reports need symbolication to be useful — Bugsly handles this automatically, giving you readable stack traces from user devices.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free