Section 15/161 menit
15. Real Use Cases
15. Real Use Cases
Use Case 1: Image Processing Pipeline dengan Region-Based Isolation
Pipeline yang mem-proses gambar besar secara background tanpa perlu membuat UIImage atau CGImage conform Sendable.
swift
import UIKit
import CoreImage
// UIImage dan CIImage tidak Sendable — tapi kita bisa transfer dengan region analysis
@MainActor
class ImageProcessingViewModel {
var processedImage: UIImage?
var isProcessing = false
func applyFilter(to image: UIImage) async {
isProcessing = true
// Transfer image ke background — setelah ini, image tidak diakses di @MainActor lagi
let result = await Task.detached {
// Image hanya diakses di sini — region aman
guard let ciImage = CIImage(image: image) else { return image }
let context = CIContext()
let filter = CIFilter.gaussianBlur()
filter.inputImage = ciImage
filter.radius = 10
guard let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else {
return image
}
return UIImage(cgImage: cgImage)
}.value
processedImage = result
isProcessing = false
}
}
Use Case 2: Database Actor dengan Re-entrancy yang Aman
Database actor yang menangani concurrent queries tanpa duplikasi atau race condition.
swift
import Foundation
struct QueryResult {
let rows: [[String: Any]]
let executionTime: TimeInterval
}
actor DatabaseActor {
private var connection: DatabaseConnection
private var activeQueries: [String: Task<QueryResult, Error>] = [:]
private var queryStats: [String: Int] = [:] // Cache hit tracking
init(connection: DatabaseConnection) {
self.connection = connection
}
// Query dengan deduplication — concurrent identical query tidak di-execute dua kali
func query(_ sql: String, parameters: [Any] = []) async throws -> QueryResult {
let cacheKey = sql + parameters.map { "\($0)" }.joined()
// Jika query identik sedang berjalan, tunggu hasilnya
if let existing = activeQueries[cacheKey] {
queryStats[cacheKey, default: 0] += 1
return try await existing.value
}
// Daftarkan task SEBELUM suspension point
let queryTask = Task<QueryResult, Error> {
let start = Date()
let rows = try await connection.execute(sql, parameters: parameters)
return QueryResult(rows: rows, executionTime: Date().timeIntervalSince(start))
}
activeQueries[cacheKey] = queryTask
do {
let result = try await queryTask.value
activeQueries.removeValue(forKey: cacheKey)
return result
} catch {
activeQueries.removeValue(forKey: cacheKey)
throw error
}
}
var deduplicationStats: [String: Int] { queryStats }
}
Use Case 3: Multi-Isolation Architecture untuk App E-Commerce
Arsitektur yang memisahkan concerns ke isolation domain berbeda untuk performa dan keamanan.
swift
import Foundation
import CoreData
// Custom actor untuk operasi database
actor DatabaseActorBody {
static let shared = DatabaseActorBody()
}
@globalActor
struct DB {
static let shared = DatabaseActorBody()
}
// Custom actor untuk network operations
actor NetworkActorBody {
static let shared = NetworkActorBody()
}
@globalActor
struct Net {
static let shared = NetworkActorBody()
}
// Database layer — hanya berjalan di DB actor
@DB
class ProductRepository {
private let context: NSManagedObjectContext
init(context: NSManagedObjectContext) {
self.context = context
}
func save(_ product: Product) throws {
let entity = ProductEntity(context: context)
entity.id = product.id
entity.name = product.name
entity.price = product.price
try context.save()
}
func fetchAll() -> [Product] {
let request = ProductEntity.fetchRequest()
let entities = (try? context.fetch(request)) ?? []
return entities.map { Product(id: $0.id!, name: $0.name!, price: $0.price) }
}
}
// Network layer — hanya berjalan di Net actor
@Net
class ProductAPIClient {
private let session = URLSession.shared
func fetchProducts() async throws -> [Product] {
let (data, _) = try await session.data(from: URL(string: "https://api.example.com/products")!)
return try JSONDecoder().decode([Product].self, from: data)
}
func uploadOrder(_ order: Order) async throws -> OrderConfirmation {
var request = URLRequest(url: URL(string: "https://api.example.com/orders")!)
request.httpMethod = "POST"
request.httpBody = try JSONEncoder().encode(order)
let (data, _) = try await session.data(for: request)
return try JSONDecoder().decode(OrderConfirmation.self, from: data)
}
}
// Coordinator di @MainActor — orkestrasi tanpa langsung sentuh DB atau Network
@MainActor
class ProductCoordinator {
private let repo: ProductRepository
private let api: ProductAPIClient
var products: [Product] = []
var isLoading = false
init(repo: ProductRepository, api: ProductAPIClient) {
self.repo = repo
self.api = api
}
func syncProducts() async {
isLoading = true
defer { isLoading = false }
do {
// Hop ke Net actor untuk fetch
let remote = try await api.fetchProducts()
// Hop ke DB actor untuk save
for product in remote {
try await repo.save(product)
}
// Kembali ke @MainActor untuk update UI
products = await repo.fetchAll()
} catch {
print("Sync gagal: \(error)")
}
}
}