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 { ... }