Files
obsidian-vault/work/wiki/apple-browsers/performance-optimization.md

408 lines
12 KiB
Markdown

---
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<String> = []
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<T>(
_ 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<mach_task_basic_info>.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