import Foundation
import UIKit
class ImageProcessor {
// Background processing with main thread updates
func processImage(_ image: UIImage, completion: @escaping (UIImage?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
// Heavy processing on background thread
let processedImage = self.applyFilters(to: image)
// Return to main thread for UI updates
DispatchQueue.main.async {
completion(processedImage)
}
}
}
private func applyFilters(to image: UIImage) -> UIImage? {
// Simulate heavy processing
Thread.sleep(forTimeInterval: 2)
return image
}
}
// Dispatch groups for coordinating multiple tasks
class DataSynchronizer {
func syncAllData(completion: @escaping (Bool) -> Void) {
let group = DispatchGroup()
var hasError = false
group.enter()
fetchPosts { success in
if !success { hasError = true }
group.leave()
}
group.enter()
fetchComments { success in
if !success { hasError = true }
group.leave()
}
group.enter()
fetchUsers { success in
if !success { hasError = true }
group.leave()
}
group.notify(queue: .main) {
completion(!hasError)
}
}
private func fetchPosts(completion: @escaping (Bool) -> Void) {
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 1)
completion(true)
}
}
private func fetchComments(completion: @escaping (Bool) -> Void) {
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 1)
completion(true)
}
}
private func fetchUsers(completion: @escaping (Bool) -> Void) {
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 1)
completion(true)
}
}
}
// Custom serial queue for thread-safe access
class ThreadSafeCache<Key: Hashable, Value> {
private var cache: [Key: Value] = [:]
private let queue = DispatchQueue(label: "com.myapp.cache", attributes: .concurrent)
func get(_ key: Key) -> Value? {
queue.sync {
cache[key]
}
}
func set(_ value: Value, forKey key: Key) {
queue.async(flags: .barrier) {
self.cache[key] = value
}
}
func remove(_ key: Key) {
queue.async(flags: .barrier) {
self.cache.removeValue(forKey: key)
}
}
}
// Debouncing with dispatch work items
class SearchDebouncer {
private var workItem: DispatchWorkItem?
private let delay: TimeInterval
init(delay: TimeInterval = 0.3) {
self.delay = delay
}
func debounce(action: @escaping () -> Void) {
workItem?.cancel()
let newWorkItem = DispatchWorkItem(block: action)
workItem = newWorkItem
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: newWorkItem)
}
}
Grand Central Dispatch (GCD) manages concurrent code execution with dispatch queues. The main queue handles UI updates—I use DispatchQueue.main.async to return to main thread after background work. Global queues provide concurrent background execution with different quality of service levels: .userInteractive, .userInitiated, .utility, and .background. Custom queues offer fine-grained control over concurrency. Dispatch groups coordinate multiple async tasks, waiting for all to complete with group.notify(). Semaphores limit concurrent access to resources. For modern Swift, async/await is preferred, but GCD remains essential for legacy code and certain use cases like debouncing and rate limiting.