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

Track up to 100 issues per month on the free plan, with unlimited events and no credit card required.

Get Started Free