Section 11/161 menit

11. Integrasi dengan UIKit dan Non-SwiftUI

11. Integrasi dengan UIKit dan Non-SwiftUI

UIKit ViewController dengan Pipeline

swift
// UIKit search dengan async pipeline
final class SearchViewController: UIViewController {
    private let searchChannel = AsyncChannel<String>()
    private var pipelineTask: Task<Void, Never>?
    private var tableView: UITableView!
    private var results: [SearchResult] = [] {
        didSet { tableView.reloadData() }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
        setupSearchBar()
        startSearchPipeline()
    }

    private func startSearchPipeline() {
        pipelineTask = Task { [weak self] in
            guard let self else { return }

            let pipeline = searchChannel
                .debounce(for: .milliseconds(300))
                .removeDuplicates()

            for await query in pipeline {
                guard !Task.isCancelled else { break }
                do {
                    let results = try await SearchAPI.search(query: query)
                    await MainActor.run {
                        self.results = results
                    }
                } catch {
                    await MainActor.run {
                        self.showError(error)
                    }
                }
            }
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        if isMovingFromParent {
            pipelineTask?.cancel()
            searchChannel.finish()
        }
    }
}

extension SearchViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        Task { await searchChannel.send(searchText) }
    }
}

extension SearchViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        results.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = results[indexPath.row].title
        return cell
    }
}

// MARK: - Placeholder
struct SearchResult: Identifiable { let id = UUID(); let title: String }
enum SearchAPI {
    static func search(query: String) async throws -> [SearchResult] { [] }
}

Sensor / IoT Data Processing

swift
// Memproses data sensor dari Bluetooth atau IoT device
actor SensorProcessor {
    private let dataChannel = AsyncChannel<SensorData>()

    func ingestData(_ data: SensorData) async {
        await dataChannel.send(data)
    }

    func startProcessing() async {
        // Pipeline: group by 5 detik → hitung statistik → simpan
        let pipeline = dataChannel
            .chunked(by: .repeating(every: .seconds(5)))

        for await window in pipeline {
            let stats = calculateStats(Array(window))
            await persistStats(stats)
        }
    }

    private func calculateStats(_ readings: [SensorData]) -> SensorStats {
        let values = readings.map(\.value)
        return SensorStats(
            count: readings.count,
            average: values.reduce(0, +) / Double(values.count),
            min: values.min() ?? 0,
            max: values.max() ?? 0,
            timestamp: Date()
        )
    }

    private func persistStats(_ stats: SensorStats) async {
        // simpan ke database
    }
}

struct SensorData { let value: Double; let timestamp: Date }
struct SensorStats {
    let count: Int; let average: Double
    let min: Double; let max: Double; let timestamp: Date
}