Section 2/101 menit
2. Directive Conditional Compilation
2. Directive Conditional Compilation
2.1 #if swift(>=X.Y) — Berdasarkan Language Version
Paling umum. Bergantung pada nilai SWIFT_VERSION di Build Settings, bukan versi Xcode:
swift
// Guard syntax dan fitur language baru
#if swift(>=6.0)
// Kode ini hanya dikompilasi saat SWIFT_VERSION = 6
func parse(_ data: Data) throws(ParseError) -> User {
// typed throws — hanya ada di Swift 6
}
#else
// Kode ini dikompilasi saat SWIFT_VERSION = 5
func parse(_ data: Data) throws -> User {
// untyped throws — kompatibel Swift 5
}
#endif
swift
// Sendable conformance yang di-enforce
#if swift(>=6.0)
struct AppConfig: Sendable {
let apiURL: URL
let timeout: TimeInterval
}
#else
struct AppConfig {
let apiURL: URL
let timeout: TimeInterval
}
#endif
2.2 #if compiler(>=X.Y) — Berdasarkan Versi Toolchain
Bergantung pada versi compiler (Xcode), bukan language version. Berguna untuk API compiler yang baru tapi tidak terkait language version:
swift
// Compiler version check — independen dari SWIFT_VERSION
#if compiler(>=6.0)
// Tersedia saat menggunakan Xcode 16+ / Swift 6 toolchain
// Meski SWIFT_VERSION masih = 5
import Observation // @Observable macro tersedia
#else
import Combine // fallback ke Combine untuk toolchain lama
#endif
Perbedaan kritis:
swift
// Skenario: Xcode 16, SWIFT_VERSION = 5
#if swift(>=6.0)
// TIDAK dikompilasi — language version masih 5
#endif
#if compiler(>=6.0)
// DIKOMPILASI — compiler adalah Xcode 16 (Swift 6 toolchain)
#endif
2.3 #if canImport() — Berdasarkan Ketersediaan Module
Paling robust untuk library/module baru. Tidak peduli versi — jika module ada, gunakan:
swift
// Module Synchronization hanya ada di Swift 6 / macOS 15 / iOS 18
#if canImport(Synchronization)
import Synchronization
struct ThreadSafeCounter {
private let value = Mutex(0)
func increment() {
value.withLock { $0 += 1 }
}
func current() -> Int {
value.withLock { $0 }
}
}
#else
import Foundation
final class ThreadSafeCounter {
private let lock = NSLock()
private var _value = 0
func increment() {
lock.withLock { _value += 1 }
}
func current() -> Int {
lock.withLock { _value }
}
}
#endif
swift
// Observation framework — @Observable macro
#if canImport(Observation)
import Observation
@Observable
class UserViewModel {
var name: String = ""
var isLoading: Bool = false
}
#else
import Combine
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
}
#endif
2.4 #if hasFeature() — Berdasarkan Fitur Language Spesifik
Cara paling granular — guard satu fitur tanpa terikat versi angka. Berguna saat fitur di-backport atau di-enable secara selektif:
swift
// Guard fitur noncopyable types
#if hasFeature(NoncopyableGenerics)
struct FileDescriptor: ~Copyable {
private let fd: Int32
init?(path: String) {
let descriptor = Darwin.open(path, O_RDONLY)
guard descriptor != -1 else { return nil }
self.fd = descriptor
}
deinit { Darwin.close(fd) }
borrowing func read(count: Int) -> Data? {
var buffer = [UInt8](repeating: 0, count: count)
let n = Darwin.read(fd, &buffer, count)
return n > 0 ? Data(buffer.prefix(n)) : nil
}
}
#else
// Fallback: class dengan manual lifecycle
final class FileDescriptor {
private let fd: Int32
init?(path: String) {
let descriptor = Darwin.open(path, O_RDONLY)
guard descriptor != -1 else { return nil }
self.fd = descriptor
}
deinit { Darwin.close(fd) }
func read(count: Int) -> Data? {
var buffer = [UInt8](repeating: 0, count: count)
let n = Darwin.read(fd, &buffer, count)
return n > 0 ? Data(buffer.prefix(n)) : nil
}
}
#endif
swift
// Guard typed throws
#if hasFeature(TypedThrows)
func validateAge(_ value: Int) throws(ValidationError) -> Int {
guard value >= 0 else { throw ValidationError.negative }
guard value <= 150 else { throw ValidationError.tooLarge }
return value
}
#else
func validateAge(_ value: Int) throws -> Int {
guard value >= 0 else { throw ValidationError.negative }
guard value <= 150 else { throw ValidationError.tooLarge }
return value
}
#endif
2.5 @available — Untuk OS Version (Bukan Language Version)
Berbeda dari #if — ini adalah runtime check dan hanya untuk API ketersediaan OS:
swift
// Bukan untuk kondisi compile — ini runtime
if #available(iOS 18.0, macOS 15.0, *) {
// Gunakan API baru
let _ = Mutex(0)
} else {
// Fallback
let _ = NSLock()
}
// Untuk deklarasi tipe: @available sebagai annotation
@available(iOS 18.0, macOS 15.0, *)
struct NewAPIWrapper {
// Hanya bisa dipakai di iOS 18+ / macOS 15+
}