Skip to content
All essays
iOSMarch 27, 202511 min

Swift Memory Management: ARC and Optimization

Master memory management in Swift. ARC, memory leaks, and performance optimization.

Ü
Ümit Uz
Mobile & Full Stack Developer

Memory management is crucial for iOS apps. Learn to manage memory effectively and avoid leaks.

ARC (Automatic Reference Counting)

How ARC Works

swift
class Person {
    let name: String
    var friends: [Person]

    init(name: String) {
        self.name = name
        self.friends = []
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

var john: Person? = Person(name: "John")
john = nil // Memory is automatically freed

Memory Leaks

Common Leak Scenarios

swift
// Retain cycle
class ViewController: UIViewController {
    var closure: (() -> Void)?

    func setupClosure() {
        // BAD: Retain cycle
        closure = {
            self.doSomething()
        }
    }

    func goodClosure() {
        // GOOD: Weak self
        closure = { [weak self] in
            self?.doSomething()
        }
    }

    func doSomething() {
        // Action
    }
}

Debugging Leaks

swift
class LeakDetector {
    static var instances: [AnyObject] = []

    static func track(_ instance: AnyObject) {
        instances.append(instance)
        print("Tracking \(instance)")
    }

    static func checkLeaks() {
        // Check for leaked instances
        print("Active instances: \(instances.count)")
    }
}

Weak References

Break Retain Cycles

swift
class MyClass: NSObject {
    var closure: (() -> Void)?

    func setupClosure() {
        // Use weak self to avoid retain cycles
        closure = { [weak self] in
            guard let self = self else {
                return
            }
            self.doSomething()
        }
    }

    func setupTimer() {
        // Use weak self in timers
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }
            self.doSomething()
        }
    }

    func doSomething() {
        // Action
    }
}

Closures

Capture Lists

swift
class ClosureManager {
    var closures: [() -> Void] = []

    func createClosures() {
        for i in 0..<10 {
            closures.append { [weak self] i in
                print("Closure \(i)")
            }
        }
    }

    func executeClosures() {
        closures.forEach { $0() }
    }
}

Performance

Memory Profiling

swift
import Foundation

class MemoryProfiler {
    func checkMemoryUsage() -> UInt64 {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(MemoryLayout.basic)
        var size: mach_msg_type_number_t = 0

        let result = withUnsafeMutablePointer(to: &info) {
            $0.withMemoryRebound(to: Int.self, capacity: 1) {
                host_statistics(mach_task_self(), $0, HOST_VM_INFO_COUNT, &count, &size)
            }
        }

        return size
    }

    func logMemoryUsage() {
        let usage = checkMemoryUsage()
        print("Memory usage: \(usage / 1024 / 1024) MB")
    }
}

Optimization

Reduce Memory Footprint

swift
class MemoryOptimizedArray<T> {
    private var array: [T] = []
    private var capacity: Int = 10

    init(capacity: Int = 10) {
        self.capacity = capacity
    }

    func append(_ element: T) {
        if array.count < capacity {
            array.append(element)
        } else {
            // Handle overflow
            print("Array is full")
        }
    }

    func remove(at index: Int) {
        array.remove(at: index)
    }

    func removeAll() {
        array.removeAll()
    }
}

Autoreleasepool

Manual Pooling

swift
class ImageProcessor {
    func processImages(_ images: [UIImage]) {
        for image in images {
            autoreleasepool {
                // Process image in autoreleasepool
                let processedImage = processImage(image)
                // Use processedImage
            }
        }
    }

    func processImage(_ image: UIImage) -> UIImage {
        // Processing logic
        return image
    }
}

Value vs Reference

Choose Wisely

swift
// Use structs for value types
struct Point {
    var x: Double
    var y: Double
}

// Use classes for reference types
class Canvas {
    var points: [Point] = []

    func addPoint(_ point: Point) {
        points.append(point)
    }
}

Best Practices

  1. 1ARC: Trust ARC for most cases
  2. 2Weak References: Use weak to break cycles
  3. 3Profiling: Profile memory usage
  4. 4Optimization: Optimize for performance
  5. 5Testing: Test for memory leaks
  6. 6Cleanup: Clean up resources
  7. 7Pooling: Reuse objects when possible
  8. 8Monitoring: Monitor memory in production

Effective memory management ensures smooth app performance!

Related essays

Next essay
Swift Threading and Concurrency: Parallel Processing