--- source: ~/DuckDuckGo/apple-browsers.git/main/.cursor/rules/performance-optimization.mdc confidence: 0.9 namespace: work last_synced: 2026-04-28 alwaysApply: false --- # Performance Optimization Guidelines ## Memory Management ### Avoid Retain Cycles ```swift // Use weak/unowned references appropriately class ViewController: UIViewController { private var timer: Timer? override func viewDidLoad() { super.viewDidLoad() // Bad - Creates retain cycle timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in self.updateUI() } // Good - Weak reference prevents retain cycle timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in self?.updateUI() } } deinit { timer?.invalidate() } } ``` ### Lazy Loading ```swift class DataManager { // Load expensive resources only when needed private lazy var database: Database = { return Database() }() // Use computed properties for lightweight calculations var itemCount: Int { return items.count } // Cache expensive computations private var _processedData: [ProcessedItem]? var processedData: [ProcessedItem] { if let cached = _processedData { return cached } let processed = items.map { ProcessedItem($0) } _processedData = processed return processed } } ``` ### Memory-Efficient Collections ```swift // Use appropriate collection types struct LargeDataSet { // Bad - Loads all data into memory var allItems: [Item] { return database.fetchAll() } // Good - Use lazy sequences var items: LazySequence<[Item]> { return database.fetchAll().lazy } // Better - Use pagination func items(page: Int, pageSize: Int = 50) -> [Item] { return database.fetch(offset: page * pageSize, limit: pageSize) } } ``` ## UI Performance ### Main Thread Protection ```swift class ImageLoader { func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) { Task { // Perform heavy work on background queue let data = try? await URLSession.shared.data(from: url).0 let image = data.flatMap { UIImage(data: $0) } // Always update UI on main thread await MainActor.run { completion(image) } } } } ``` ### Efficient Table/Collection Views ```swift class OptimizedTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() // Register reusable cells tableView.register(CustomCell.self, forCellReuseIdentifier: "Cell") // Set estimated heights for better scrolling tableView.estimatedRowHeight = 44.0 tableView.rowHeight = UITableView.automaticDimension // Enable prefetching tableView.prefetchDataSource = self } // Reuse cells efficiently override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell // Configure cell with minimal work cell.configure(with: items[indexPath.row]) // Cancel any ongoing async work cell.prepareForReuse() return cell } } extension OptimizedTableViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { // Preload data for upcoming cells let urls = indexPaths.compactMap { items[$0.row].imageURL } ImageCache.shared.preload(urls: urls) } } ``` ### Image Optimization ```swift extension UIImage { // Resize images to appropriate size func resized(to targetSize: CGSize) -> UIImage? { let renderer = UIGraphicsImageRenderer(size: targetSize) return renderer.image { _ in self.draw(in: CGRect(origin: .zero, size: targetSize)) } } // Decode images on background queue func decodedImage() -> UIImage? { guard let cgImage = cgImage else { return nil } let colorSpace = CGColorSpaceCreateDeviceRGB() let context = CGContext( data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8, bytesPerRow: cgImage.width * 4, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: cgImage.width, height: cgImage.height)) guard let decodedImage = context?.makeImage() else { return nil } return UIImage(cgImage: decodedImage) } } ``` ## Network Performance ### Efficient API Calls ```swift class APIClient { private let session: URLSession private let cache = URLCache( memoryCapacity: 10 * 1024 * 1024, // 10 MB diskCapacity: 50 * 1024 * 1024, // 50 MB diskPath: nil ) init() { let configuration = URLSessionConfiguration.default configuration.urlCache = cache configuration.requestCachePolicy = .returnCacheDataElseLoad configuration.timeoutIntervalForRequest = 30 configuration.httpMaximumConnectionsPerHost = 5 self.session = URLSession(configuration: configuration) } // Batch requests when possible func fetchMultipleItems(ids: [String]) async throws -> [Item] { // Bad - Multiple individual requests // let items = try await ids.asyncMap { try await fetchItem(id: $0) } // Good - Single batch request let request = BatchRequest(ids: ids) return try await fetch(request) } // Use compression func createRequest(url: URL) -> URLRequest { var request = URLRequest(url: url) request.addValue("gzip, deflate", forHTTPHeaderField: "Accept-Encoding") return request } } ``` ### Download Optimization ```swift class DownloadManager { // Use background sessions for large downloads private lazy var backgroundSession: URLSession = { let configuration = URLSessionConfiguration.background(withIdentifier: "com.duckduckgo.downloads") configuration.isDiscretionary = true configuration.sessionSendsLaunchEvents = true return URLSession(configuration: configuration, delegate: self, delegateQueue: nil) }() // Resume interrupted downloads func resumeDownload(from resumeData: Data) { let task = backgroundSession.downloadTask(withResumeData: resumeData) task.resume() } // Limit concurrent downloads private let downloadQueue = OperationQueue() init() { downloadQueue.maxConcurrentOperationCount = 3 } } ``` ## Database Performance ### Efficient Queries ```swift import GRDB class DatabaseManager { // Use indexes for frequently queried columns func createIndexes(_ db: Database) throws { try db.create(index: "idx_bookmarks_url", on: "bookmarks", columns: ["url"]) try db.create(index: "idx_history_date", on: "history", columns: ["visitDate"]) } // Batch operations func insertMultipleItems(_ items: [Item]) throws { try dbQueue.write { db in // Use transactions for bulk operations try items.forEach { item in try item.insert(db) } } } // Use appropriate fetch limits func fetchRecentHistory(limit: Int = 100) throws -> [HistoryItem] { try dbQueue.read { db in try HistoryItem .order(Column("visitDate").desc) .limit(limit) .fetchAll(db) } } // Optimize complex queries func searchBookmarks(query: String) throws -> [Bookmark] { try dbQueue.read { db in // Use FTS (Full Text Search) for text searching let pattern = "%\(query)%" return try Bookmark .filter(Column("title").like(pattern) || Column("url").like(pattern)) .limit(50) .fetchAll(db) } } } ``` ## Algorithm Optimization ### Use Efficient Data Structures ```swift // Choose appropriate data structures class URLMatcher { // Bad - O(n) lookup private var blockedURLs: [String] = [] func isBlocked(_ url: String) -> Bool { return blockedURLs.contains(url) } // Good - O(1) lookup private var blockedURLSet: Set = [] func isBlockedOptimized(_ url: String) -> Bool { return blockedURLSet.contains(url) } } ``` ### Avoid Expensive Operations ```swift extension Array { // Bad - Creates multiple intermediate arrays func processItems() -> [ProcessedItem] { return self .compactMap { $0 as? Item } .filter { $0.isValid } .map { ProcessedItem($0) } .sorted { $0.priority > $1.priority } } // Good - Use lazy evaluation func processItemsOptimized() -> [ProcessedItem] { return self.lazy .compactMap { $0 as? Item } .filter { $0.isValid } .map { ProcessedItem($0) } .sorted { $0.priority > $1.priority } } } ``` ## Monitoring and Profiling ### Performance Metrics ```swift class PerformanceMonitor { static func measure( _ title: String, operation: () throws -> T ) rethrows -> T { let startTime = CFAbsoluteTimeGetCurrent() defer { let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime print("⏱ \(title): \(timeElapsed)s") // Log slow operations if timeElapsed > 1.0 { Pixel.fire(.performanceWarning(operation: title, duration: timeElapsed)) } } return try operation() } } // Usage let results = PerformanceMonitor.measure("Database Query") { try database.fetchAllBookmarks() } ``` ### Memory Monitoring ```swift class MemoryMonitor { static var currentMemoryUsage: Double { var info = mach_task_basic_info() var count = mach_msg_type_number_t(MemoryLayout.size) / 4 let result = withUnsafeMutablePointer(to: &info) { $0.withMemoryRebound(to: integer_t.self, capacity: 1) { task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count) } } return result == KERN_SUCCESS ? Double(info.resident_size) / 1024.0 / 1024.0 : 0 } static func logMemoryUsage(_ context: String) { let usage = currentMemoryUsage print("💾 Memory usage (\(context)): \(usage) MB") if usage > 200 { // 200 MB threshold Pixel.fire(.highMemoryUsage(context: context, usage: usage)) } } } ``` ## Best Practices Summary 1. **Profile First**: Use Instruments to identify actual bottlenecks 2. **Measure Impact**: Quantify performance improvements 3. **Cache Wisely**: Cache expensive computations but watch memory usage 4. **Async Everything**: Keep UI responsive with background processing 5. **Batch Operations**: Combine multiple operations when possible 6. **Lazy Loading**: Load data only when needed 7. **Resource Management**: Release resources promptly 8. **Monitor Production**: Track performance metrics in production