iOS Runtime — lingkungan eksekusi aplikasi pada sistem operasi Apple iOS, yang mencakup Objective-C Runtime, Swift Runtime, kerangka kerja Cocoa Touch dan mekanisme manajemen memori melalui Automatic Reference Counting (ARC). iOS Runtime bertanggung jawab atas pengikatan metode secara dinamis (message passing), pemuatan kelas, manajemen memori dan interaksi dengan perangkat keras melalui kerangka kerja iOS. Menurut Apple Developer Documentation, pemahaman tentang runtime diperlukan untuk optimasi kinerja, debugging dan pengembangan aplikasi iOS yang stabil.
Hal utama
iOS Runtime — kumpulan komponen sistem yang memastikan eksekusi aplikasi pada perangkat Apple di bawah iOS. Mencakup Objective-C Runtime (pustaka libobjc.A.dylib), Swift Runtime (libswiftCore.dylib), Core Foundation, kerangka kerja Cocoa Touch (UIKit, Foundation), pemuat dinamis dyld dan lingkungan runtime untuk manajemen memori, thread dan komunikasi antar-proses.
Secara arsitektur, iOS Runtime bekerja pada tiga tingkat. Pada tingkat bawah — format biner Mach-O dan dyld, yang memuat file yang dapat dieksekusi dan pustaka. Tingkat menengah — Objective-C Runtime dan Swift Runtime, yang bertanggung jawab atas dispatch metode dan manajemen objek. Tingkat atas — kerangka kerja Cocoa Touch (UIKit, Foundation, Core Data, Metal), yang menyediakan API untuk pengembang.
Pemahaman tentang iOS Runtime memungkinkan pengembang untuk menyelesaikan tugas-tugas kompleks: swizzling metode (Method Swizzling) untuk pengujian A/B dan analitik, pemuatan kelas dinamis, optimasi memori melalui pemahaman ARC, debugging retain cycles dan kebocoran memori, optimasi waktu mulai aplikasi melalui dyld. Tanpa pengetahuan runtime, profiling dan optimasi pada tingkat sistem tidak mungkin dilakukan.
| Komponen | Pustaka | Tujuan |
|---|---|---|
| Objective-C Runtime | libobjc.A.dylib | Message passing, kelas dinamis, swizzling |
| Swift Runtime | libswiftCore.dylib | Value types, generics, protocol witnesses |
| Core Foundation | CoreFoundation.framework | CFType, toll-free bridging |
| dyld | dyld (usr/lib/dyld) | Pemuatan Mach-O, pengikatan pustaka |
| libSystem | libSystem.B.dylib | POSIX threads, libc, libdispatch (GCD) |
Aplikasi untuk iOS dikompilasi ke dalam format Mach-O (Mach Object). File Mach-O berisi header (header), perintah pemuatan (load commands) dan segmen (segments): __TEXT (kode, konstanta), __DATA (variabel global, metadata Objective-C), __LINKEDIT (simbol, tabel relokasi). dyld menganalisis Mach-O dan memuat dependensi sebelum mengeksekusi instruksi pertama.
Objective-C Runtime — bagian terkuat dari iOS Runtime. Tidak seperti C++ dengan pengikatan awal (early binding), Objective-C menggunakan pengikatan akhir (late binding) melalui message passing. Pemanggilan metode [receiver message] dikompilasi bukan sebagai pemanggilan fungsi langsung, tetapi sebagai objc_msgSend(receiver, @selector(message)), yang secara dinamis menemukan implementasi metode di kelas objek.
Setiap objek Objective-C menyimpan pointer isa ke kelasnya. Kelas berisi daftar metode (method list), cache metode (method cache) dan pointer ke superkelas. objc_msgSend menelusuri rantai pewarisan: memeriksa cache kelas, kemudian method list, lalu beralih ke superkelas. Jika metode tidak ditemukan, forward diaktifkan: resolveInstanceMethod, forwardingTargetForSelector dan forwardInvocation.
Method Swizzling — teknik mengganti implementasi metode dengan cepat melalui pertukaran IMP (implementation pointer) di runtime. Digunakan untuk pengujian A/B, analitik (pelacakan layar otomatis) dan pemantauan. Tidak disarankan dalam produksi tanpa kebutuhan mendesak, karena dapat bertentangan dengan pembaruan sistem operasi.
// Method Swizzling untuk pelacakan viewDidLoad
#import
@implementation UIViewController (Tracking)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewDidLoad);
SEL swizzledSelector = @selector(swizzled_viewDidLoad);
Method originalMethod = class_getInstanceMethod(
class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(
class, swizzledSelector);
BOOL didAddMethod = class_addMethod(
class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod)
);
if (didAddMethod) {
class_replaceMethod(
class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod)
);
} else {
method_exchangeImplementations(
originalMethod, swizzledMethod);
}
});
}
- (void)swizzled_viewDidLoad {
// Pelacakan peristiwa
NSLog(@"View Did Load: %@", self.class);
// Memanggil implementasi asli
[self swizzled_viewDidLoad];
}
@end Kategori UIViewController (Tracking) mengganti viewDidLoad dengan swizzled_viewDidLoad di semua UIViewController dalam aplikasi. dispatch_once menjamin swizzling satu kali. class_addMethod mencegah swizzling ganda dan konflik dengan superkelas. Digunakan untuk pelacakan otomatis tampilan layar dalam analitik tanpa mengubah kode sumber pengontrol.
Di iOS modern (arm64), Apple telah mengoptimalkan pointer isa: ini bukan sekadar alamat kelas, tetapi bidang bit (non-pointer isa) yang berisi flag manajemen memori dan informasi tentang kelas. Tagged pointers — optimasi lain: nilai NSNumber, NSDate dan NSString berukuran kecil disimpan bukan sebagai objek di heap, tetapi langsung di pointer, menghilangkan overhead malloc dan retain/release. tagged pointer dikenali dari bit paling tidak signifikan dari isa.
Swift Runtime berbeda secara fundamental dari Objective-C Runtime: Swift secara default menggunakan dispatch statis (static dispatch) melalui vtable untuk metode kelas dan direct call untuk value types dan extension methods. Dispatch dinamis (dynamic dispatch) hanya digunakan untuk metode yang ditandai dengan @objc atau dynamic. Ini memberikan peningkatan kinerja hingga 40% dibandingkan dengan Objective-C.
Value types (struct, enum) di Swift — perbedaan utama dari Objective-C. Mereka disimpan di stack (stack) atau di dalam objek lain, tidak menggunakan retain/release dan tidak berpartisipasi dalam ARC untuk penghitung referensi. Struct tidak memiliki pointer isa dan tidak dapat dikirim melalui objc_msgSend. Protocol witnesses — analog vtable untuk protokol, memungkinkan dispatch dinamis untuk existential container.
Swift Runtime juga mencakup generics dengan reifikasi (reified generics melalui mangled symbols) dan COW (Copy-on-Write) untuk optimasi string, array, dictionary, set. Saat menyalin koleksi, penyalinan sebenarnya hanya terjadi ketika salah satu salinan dimodifikasi. Ini meminimalkan overhead saat meneruskan koleksi antar fungsi.
import Foundation
// Swift: dispatch statis (vtable untuk class)
class Animal {
func makeSound() { print("...") } // vtable
}
class Dog: Animal {
override func makeSound() { print("Woof") } // vtable override
}
// @objc dynamic: Objective-C Runtime dispatch
class Cat: Animal {
@objc dynamic override func makeSound() {
print("Meow")
} // objc_msgSend
}
// Struct — no runtime dispatch
struct Cow {
func makeSound() { print("Moo") } // direct call
}
// Protocol with protocol witness
protocol SoundMaker {
func makeSound()
}
struct Duck: SoundMaker {
func makeSound() { print("Quack") }
}
// Penggunaan existential container
let soundMakers: [SoundMaker] = [Dog(), Cow(), Duck()]
for maker in soundMakers {
maker.makeSound() // protocol witness dispatch
}
// Pengujian kinerja
func testDispatch() {
let dog = Dog()
let cat = Cat()
var cow = Cow()
let start = CFAbsoluteTimeGetCurrent()
for _ in 0..<1000000 {
dog.makeSound() // vtable: ~3ns
cat.makeSound() // objc_msgSend: ~15ns
cow.makeSound() // direct: ~1ns
}
let elapsed = CFAbsoluteTimeGetCurrent() - start
print("Elapsed: (elapsed) sec")
}Contoh menunjukkan tiga jenis dispatch di Swift: vtable untuk class (Dog), objc_msgSend untuk @objc dynamic (Cat) dan direct call untuk struct (Cow). Protocol witnesses di existential container ([SoundMaker]) menambahkan overhead. Dalam praktiknya, Swift memilih dispatch statis di mana pun memungkinkan, memberikan kinerja mendekati C.
Swift Runtime dirancang untuk kompatibilitas penuh dengan Objective-C Runtime. Setiap kelas Swift yang mewarisi NSObject secara otomatis terdaftar di Objective-C Runtime dan dapat dipanggil melalui objc_msgSend. Atribut @objc membuat metode Swift dapat diakses dari Objective-C. Jembatan String: Swift String secara otomatis dijembatani ke NSString saat diteruskan ke API Objective-C (toll-free bridging).
ARC (Automatic Reference Counting) — sistem manajemen memori di iOS, yang bekerja pada tahap kompilasi. Kompiler (Clang) menganalisis siklus hidup objek dan secara otomatis menyisipkan panggilan retain/release/autorelease. Pengembang tidak perlu memanggilnya secara manual — tidak seperti Manual Retain-Release (MRR) sebelum iOS 5. ARC bekerja pada tingkat objek Objective-C dan Swift class, tetapi tidak untuk value types (struct, enum).
Setiap objek Objective-C dan Swift class memiliki penghitung referensi (retain count), yang disimpan di bidang extra_rc di dalam non-pointer isa. Saat objek dibuat, retain count = 1. Saat retain, penghitung bertambah; saat release, berkurang. Ketika penghitung mencapai 0, objek didealokasi melalui dealloc (Objective-C) atau deinit (Swift). ARC thread-safe: retain/release menggunakan operasi atomik (OSAtomicIncrement32/OSAtomicDecrement32).
Retain cycles — masalah utama ARC. Jika objek A menyimpan referensi strong ke B, dan B — referensi strong ke A, kedua objek tidak akan pernah didealokasi karena penghitung referensi mereka tidak akan menjadi nol. Solusinya — referensi lemah (__weak di Objective-C, weak di Swift) atau unowned. Referensi lemah tidak meningkatkan retain count dan secara otomatis menjadi nol (nil) saat dealokasi objek.
import Foundation
// Contoh retain cycle
class Parent {
var child: Child?
deinit { print("Parent deallocated") }
}
class Child {
var parent: Parent? // strong — membuat retain cycle!
deinit { print("Child deallocated") }
}
var parent: Parent? = Parent()
var child: Child? = Child()
parent?.child = child
child?.parent = parent // siklus: Parent -> Child -> Parent
parent = nil
child = nil
// deinit TIDAK dipanggil — kebocoran memori!
// Perbaikan: weak
class WeakChild {
weak var parent: Parent? // weak — tidak meningkatkan retain count
deinit { print("WeakChild deallocated") }
}
// Perbaikan: unowned (untuk masa hidup terjamin)
class UnownedChild {
unowned let parent: Parent
init(parent: Parent) { self.parent = parent }
deinit { print("UnownedChild deallocated") }
}
// Pemeriksaan melalui Instruments
func profileMemory() {
// 1. Jalankan Instruments > Leaks
// 2. Lakukan tindakan yang membuat objek
// 3. Periksa Leaks untuk kebocoran
// 4. Di Allocations temukan objek tanpa dealloc
for _ in 0..<1000 {
let p = Parent()
let c = WeakChild()
p.child = c as? Child
// c.parent = p — TIDAK ditambahkan, weak
}
}Contoh retain cycle antara Parent dan Child: keduanya menyimpan referensi strong satu sama lain, ARC tidak dapat menghilangkan penghitung. Perbaikan — weak parent di Child. weak secara otomatis menjadi nol saat dealokasi parent. unowned — untuk kasus di mana masa hidup parent dijamin lebih lama dari child (misalnya, viewController dan view). Gunakan Instruments > Leaks untuk mendeteksi retain cycles pada tahap awal.
Autorelease pool — mekanisme release tertunda untuk objek yang dibuat tanpa kepemilikan eksplisit. @autoreleasepool { } di Swift dan Objective-C membuat pool yang dikosongkan di akhir blok, mengirim release ke setiap objek di pool. Sangat penting dalam loop (membuat ribuan objek sementara) dan di thread latar belakang tanpa RunLoop. UIKit RunLoop secara otomatis mengosongkan autorelease pool utama pada setiap iterasi.
dyld (dynamic link editor) — pemuat sistem yang bertanggung jawab untuk memuat file yang dapat dieksekusi Mach-O dan pustaka dinamis terkait (dylib) saat memulai aplikasi iOS. dyld terletak di /usr/lib/dyld dan merupakan bagian dari libSystem. Proses pemuatan mencakup beberapa tahap: penguraian Mach-O, pemuatan dependensi (Library Loader, LC_LOAD_DYLIB), relokasi alamat (ASLR), inisialisasi Objective-C Runtime dan panggilan main().
Waktu mulai aplikasi (launch time) secara kritis tergantung pada dyld: semakin banyak pustaka dinamis dan kelas Objective-C, semakin lama pre-main time. Apple merekomendasikan untuk meminimalkan jumlah metode +load (dieksekusi sebelum main), menggantinya dengan +initialize (inisialisasi malas). Sejak 2020, Apple menggunakan prebuilt dyld cache di iOS: pustaka sistem telah ditautkan sebelumnya dalam satu cache, yang mempercepat pemuatan.
import Foundation
// Mengukur waktu startup melalui DYLD_PRINT_STATISTICS
// Di Xcode: Edit Scheme > Run > Arguments > Environment Variables
// DYLD_PRINT_STATISTICS = 1
// DYLD_PRINT_STATISTICS_DETAILS = 1
// Pengukuran pre-main time secara programatik
@main
struct AppMain {
static func main() {
let launchStart = CFAbsoluteTimeGetCurrent()
// UIApplicationMain terjadi di sini
AppDelegate.main()
let launchEnd = CFAbsoluteTimeGetCurrent()
let preMainTime = launchEnd - launchStart
print("Pre-main time: (preMainTime) sec")
}
}
// Optimasi: mengganti +load dengan +initialize
class OptimizedClass {
// ❌ +load dieksekusi sebelum main
// override class func load() { }
// ✅ +initialize dieksekusi saat penggunaan pertama
static let shared = OptimizedClass()
private init() {
// Inisialisasi di sini
}
}
// Optimasi jumlah dylib
// Menggabungkan pustaka statis mengurangi jumlah LC_LOAD_DYLIB
// Gunakan flag -ObjC untuk menautkan hanya kelas Objective-C yang digunakan
// Xcode: Build Settings > Mach-O Type > Static LibraryUntuk mengukur pre-main time gunakan DYLD_PRINT_STATISTICS di skema Xcode. Output akan menampilkan total time, dylib loading time, rebase/bind time, Objective-C setup time dan initializer time. Nilai target: total < 400ms untuk start dingin, < 200ms untuk start hangat. Optimasi: menggabungkan pustaka, mengganti +load dengan +initialize, mengurangi jumlah kelas Objective-C (gunakan Swift), jumlah minimal kerangka kerja dinamis.
dyld shared cache — cache pustaka sistem yang telah ditautkan sebelumnya di iOS. Semua dylib sistem (UIKit, Foundation, CoreGraphics) digabungkan menjadi satu file: /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64. Ini menghilangkan kebutuhan untuk memuat setiap pustaka sistem secara terpisah — dyld mengakses cache, yang secara signifikan mempercepat startup. Aplikasi dengan 10+ kerangka kerja dinamis mengalami penundaan terbesar karena dylib kustom tidak termasuk dalam dsc.
Pertanyaan yang sering diajukan
iOS Runtime — lingkungan eksekusi aplikasi di iOS, mencakup Objective-C Runtime (libobjc.dylib), Swift Runtime (libswiftCore.dylib), kerangka kerja Cocoa Touch, dyld (pemuat dinamis) dan ARC (manajemen memori). Menyediakan message passing untuk Objective-C, dispatch statis untuk Swift, pemuatan file Mach-O dan manajemen memori otomatis.
Objective-C Runtime menggunakan pengikatan dinamis melalui objc_msgSend (message passing) dengan pengikatan akhir. Swift Runtime menggunakan dispatch statis (vtable untuk kelas, direct call untuk struct) untuk kinerja. @objc dynamic mengaktifkan Objective-C Runtime untuk kelas Swift. Swift struct tidak memiliki pointer isa dan tidak menggunakan retain/release.
ARC (Automatic Reference Counting) — manajemen memori pada tahap kompilasi. Kompiler Clang secara otomatis menyisipkan panggilan retain/release. Setiap objek memiliki penghitung referensi, saat nol dealloc dipanggil. Retain cycles (referensi strong timbal balik) dicegah dengan referensi weak/unowned. Gunakan Instruments > Leaks untuk mendeteksi kebocoran.
dyld — pemuat dinamis file Mach-O. Memuat file yang dapat dieksekusi dan semua dylib yang tergantung, melakukan relokasi (ASLR), menginisialisasi Objective-C Runtime dan memanggil main(). Pre-main time tergantung pada jumlah dylib dan metode +load. Gunakan DYLD_PRINT_STATISTICS untuk pengukuran. Optimasi: menggabungkan pustaka, mengganti +load dengan +initialize.
Method Swizzling — teknik mengganti IMP (implementation pointer) metode dengan cepat melalui Objective-C Runtime class_getInstanceMethod dan method_exchangeImplementations. Digunakan untuk pengujian A/B, analitik (pelacakan layar otomatis) dan pemantauan. Tidak disarankan dalam produksi tanpa kebutuhan mendesak. Di Swift diganti dengan @objc dynamic + Method Swizzling.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga