Section 9/161 menit

9. Interoperability — ObjC, C, dan Legacy Code

9. Interoperability — ObjC, C, dan Legacy Code

ObjC Types dan Sendability

swift
// Banyak ObjC types sudah di-annotate sebagai Sendable di SDK
// Tapi beberapa perlu penanganan khusus

// DispatchQueue — Sendable (built-in)
let queue: DispatchQueue = .global()
Task { _ = queue }  // ✓

// NSOperationQueue — perlu @unchecked jika dipakai sebagai Sendable
extension OperationQueue: @unchecked Sendable { }

// Custom ObjC class — bisa annotate dengan @MainActor jika main-thread only
@MainActor
class LegacyViewController: UIViewController {
    // Semua property dan method otomatis @MainActor
}

// @preconcurrency untuk import yang belum di-update
@preconcurrency import ThirdPartyLibrary

// Ini suppress warning untuk ThirdPartyClass yang belum Sendable
func useThirdParty(_ obj: ThirdPartyClass) async {
    await someActor.process(obj)  // warning di-suppress oleh @preconcurrency
}

C Interop dan Unsafe Patterns

swift
// C function pointers — tidak bisa capture context
// Harus menggunakan global state atau UnsafePointer trick
typealias CCallback = @convention(c) (UnsafeRawPointer?) -> Void

// Unsafe: menggunakan unmanaged reference untuk bridging
class CallbackBridge {
    var onEvent: ((Event) -> Void)?
    
    func register() {
        let ptr = Unmanaged.passRetained(self).toOpaque()
        // C function yang menerima context pointer
        registerCCallback(ptr, { rawPtr in
            guard let ptr = rawPtr else { return }
            let bridge = Unmanaged<CallbackBridge>.fromOpaque(ptr).takeUnretainedValue()
            // ⚠️ Ini berjalan di C callback thread — belum tentu main thread
            DispatchQueue.main.async {
                bridge.onEvent?(.received)
            }
        })
    }
    
    deinit {
        unregisterCCallback()
    }
}

@preconcurrency dan Gradual Migration

swift
// Untuk library yang bertahap migrasi ke Swift 6

// API lama yang belum Sendable
public class LegacyNetworkSession {
    public func fetch(url: URL, completion: @escaping (Data?) -> Void) { }
}

// Wrapper modern yang type-safe
public actor ModernNetworkSession {
    private let legacy: LegacyNetworkSession
    
    public init() {
        legacy = LegacyNetworkSession()
    }
    
    public func fetch(url: URL) async throws -> Data {
        try await withCheckedThrowingContinuation { continuation in
            legacy.fetch(url: url) { data in
                if let data {
                    continuation.resume(returning: data)
                } else {
                    continuation.resume(throwing: NetworkError.noData)
                }
            }
        }
    }
}

// @preconcurrency import untuk modul yang belum Swift 6
@preconcurrency import LegacyFramework

// Supresses Sendable warnings untuk types dari LegacyFramework
func useLegacy(session: LegacyNetworkSession) async { ... }