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 freedMemory 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
- 1ARC: Trust ARC for most cases
- 2Weak References: Use weak to break cycles
- 3Profiling: Profile memory usage
- 4Optimization: Optimize for performance
- 5Testing: Test for memory leaks
- 6Cleanup: Clean up resources
- 7Pooling: Reuse objects when possible
- 8Monitoring: Monitor memory in production
Effective memory management ensures smooth app performance!