iOS Runtime: ano ito, kapaligiran ng pagpapatupad ng aplikasyon sa iPhone

May-akda: IT Sectr Nai-publish: 2026-05-17 Oras ng pagbabasa: 12 min

iOS Runtime — kapaligiran ng pagpapatupad ng mga aplikasyon sa operating system na Apple iOS, kabilang ang Objective-C Runtime, Swift Runtime, mga framework ng Cocoa Touch at mga mekanismo ng pamamahala ng memorya sa pamamagitan ng Automatic Reference Counting (ARC). Ang iOS Runtime ay responsable para sa dynamic na pagbubuklod ng mga pamamaraan (message passing), pag-load ng mga klase, pamamahala ng memorya at pakikipag-ugnayan sa hardware sa pamamagitan ng mga framework ng iOS. Ayon sa Apple Developer Documentation, ang pag-unawa sa runtime ay kinakailangan para sa pag-optimize ng pagganap, pag-debug at pag-develop ng mga matatag na aplikasyon sa iOS.

Mga pangunahing puntos

  • iOS Runtime — kapaligiran ng pagpapatupad ng aplikasyon, kabilang ang Objective-C Runtime, Swift Runtime at Cocoa Touch
  • Objective-C Runtime — dynamic na pagbubuklod ng pamamaraan sa pamamagitan ng message passing (objc_msgSend)
  • Swift Runtime — static na dispatch na may mga pag-optimize sa pamamagitan ng value types at generics
  • ARC (Automatic Reference Counting) — awtomatikong pamamahala ng memorya sa yugto ng kompilasyon
  • dyld — dynamic na tagapag-load na naglo-load ng mga framework at library sa pagsisimula ng aplikasyon

Ano ang iOS Runtime?

iOS Runtime — ang koleksyon ng mga bahagi ng sistema na nagsisiguro sa pagpapatupad ng mga aplikasyon sa mga Apple device sa ilalim ng iOS. Kabilang dito ang Objective-C Runtime (library libobjc.A.dylib), Swift Runtime (libswiftCore.dylib), Core Foundation, mga framework ng Cocoa Touch (UIKit, Foundation), dynamic na tagapag-load na dyld at runtime na kapaligiran para sa pamamahala ng memorya, mga thread at interprocess na komunikasyon.

Sa arkitektura, ang iOS Runtime ay gumagana sa tatlong antas. Sa ibabang antas — ang Mach-O binary na format at dyld, na naglo-load ng executable file at mga library. Sa gitnang antas — Objective-C Runtime at Swift Runtime, responsable para sa dispatch ng pamamaraan at pamamahala ng mga bagay. Sa itaas na antas — mga framework ng Cocoa Touch (UIKit, Foundation, Core Data, Metal), na nagbibigay ng API para sa developer.

Ang pag-unawa sa iOS Runtime ay nagpapahintulot sa developer na malutas ang mga kumplikadong gawain: swizzling ng pamamaraan (Method Swizzling) para sa A/B testing at analytics, dynamic na pag-load ng mga klase, pag-optimize ng memorya sa pamamagitan ng pag-unawa sa ARC, pag-debug ng mga retain cycle at pagtagas ng memorya, pag-optimize ng oras ng pagsisimula ng aplikasyon sa pamamagitan ng dyld. Kung walang kaalaman sa runtime, imposible ang profiling at pag-optimize sa antas ng sistema.

Mga bahagi ng iOS Runtime

BahagiLibraryLayunin
Objective-C Runtimelibobjc.A.dylibMessage passing, dynamic na mga klase, swizzling
Swift RuntimelibswiftCore.dylibValue types, generics, protocol witnesses
Core FoundationCoreFoundation.frameworkCFType, toll-free bridging
dylddyld (usr/lib/dyld)Pag-load ng Mach-O, pagbubuklod ng library
libSystemlibSystem.B.dylibPOSIX threads, libc, libdispatch (GCD)

Format ng Mach-O

Ang mga aplikasyon para sa iOS ay nako-compile sa Mach-O format (Mach Object). Ang file na Mach-O ay naglalaman ng header (header), mga command ng pag-load (load commands) at mga segment (segments): __TEXT (code, constants), __DATA (global variables, Objective-C metadata), __LINKEDIT (mga simbolo, mga talahanayan ng relocation). Sinusuri ng dyld ang Mach-O at nilo-load ang mga dependency bago isagawa ang unang instruction.

Objective-C Runtime: message passing at dynamic na dispatch

Objective-C Runtime — ang pinakamalakas na bahagi ng iOS Runtime. Hindi tulad ng C++ na may maagang pagbubuklod (early binding), ang Objective-C ay gumagamit ng huling pagbubuklod (late binding) sa pamamagitan ng message passing. Ang tawag sa pamamaraan [receiver message] ay hindi nako-compile bilang direktang tawag ng function, kundi bilang objc_msgSend(receiver, @selector(message)), na dynamic na hinahanap ang implementasyon ng pamamaraan sa klase ng bagay.

Bawat Objective-C na bagay ay nag-iimbak ng isa pointer sa klase nito. Ang klase ay naglalaman ng listahan ng pamamaraan (method list), cache ng pamamaraan (method cache) at pointer sa superklase. Ang objc_msgSend ay dumadaan sa chain ng pamana: sinusuri ang cache ng klase, pagkatapos ang method list, pagkatapos ay pumunta sa superklase. Kung hindi natagpuan ang pamamaraan, ang forward ay isinaaktibo: resolveInstanceMethod, forwardingTargetForSelector at forwardInvocation.

Method Swizzling — teknik ng pagpapalit ng implementasyon ng pamamaraan sa pamamagitan ng pagpapalitan ng IMP (implementation pointer) sa runtime. Ginagamit para sa A/B testing, analytics (awtomatikong pagsubaybay ng mga screen) at monitoring. Hindi inirerekomenda sa produksyon nang walang matinding pangangailangan, dahil maaaring sumalungat sa mga update ng operating system.

Halimbawa: Method Swizzling sa Objective-C

objective-c
// Method Swizzling para sa pagsubaybay ng 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 {
    // Pagsubaybay ng kaganapan
    NSLog(@"View Did Load: %@", self.class);
    // Pagtawag ng orihinal na implementasyon
    [self swizzled_viewDidLoad];
}

@end

Ang kategoryang UIViewController (Tracking) ay pinapalitan ang viewDidLoad ng swizzled_viewDidLoad sa lahat ng UIViewController sa aplikasyon. Ginagarantiyahan ng dispatch_once ang isang beses na swizzling. Pinipigilan ng class_addMethod ang dobleng swizzling at mga salungatan sa mga superklase. Ginagamit para sa awtomatikong pagsubaybay ng pagpapakita ng screen sa analytics nang hindi binabago ang source code ng mga controller.

Isa pointer at tagged pointers

Sa modernong iOS (arm64), na-optimize ng Apple ang isa pointer: hindi lang ito address ng klase, kundi isang bit field (non-pointer isa) na naglalaman ng mga flag ng pamamahala ng memorya at impormasyon tungkol sa klase. Ang Tagged pointers — isa pang pag-optimize: ang mga halaga ng NSNumber, NSDate at NSString na maliit ang sukat ay iniimbak hindi bilang mga bagay sa heap, kundi direkta sa pointer, na nag-aalis ng overhead ng malloc at retain/release. Ang tagged pointer ay nakikilala sa pamamagitan ng hindi gaanong makabuluhang bit ng isa.

Swift Runtime: static na dispatch at pag-optimize

Swift Runtime ay pangunahing naiiba sa Objective-C Runtime: ang Swift ay gumagamit ng default na static na dispatch sa pamamagitan ng vtable para sa mga pamamaraan ng klase at direct call para sa value types at extension methods. Ang dynamic na dispatch ay ginagamit lamang para sa mga pamamaraan na may markang @objc o dynamic. Nagbibigay ito ng pagtaas ng pagganap ng hanggang 40% kumpara sa Objective-C.

Value types (struct, enum) sa Swift — pangunahing pagkakaiba sa Objective-C. Ang mga ito ay iniimbak sa stack o sa loob ng ibang bagay, hindi gumagamit ng retain/release at hindi lumalahok sa ARC para sa bilang ng reference. Ang Struct ay walang isa pointer at hindi maaaring ipadala sa pamamagitan ng objc_msgSend. Ang Protocol witnesses — katumbas ng vtable para sa mga protocol, na nagpapahintulot ng dynamic na dispatch para sa existential container.

Ang Swift Runtime ay kasama rin ang generics na may reification (reified generics sa pamamagitan ng mangled symbols) at COW (Copy-on-Write) para sa pag-optimize ng string, array, dictionary, set. Sa pagkopya ng koleksyon, ang aktwal na pagkopya ay nangyayari lamang kapag binago ang isa sa mga kopya. Pinapaliit nito ang overhead sa pagpapasa ng mga koleksyon sa pagitan ng mga function.

Swift vs Objective-C dispatch

swift
import Foundation

// Swift: static na dispatch (vtable para sa 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") }
}

// Paggamit ng existential container
let soundMakers: [SoundMaker] = [Dog(), Cow(), Duck()]
for maker in soundMakers {
    maker.makeSound()  // protocol witness dispatch
}

// Pagsubok ng pagganap
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")
}

Ang halimbawa ay nagpapakita ng tatlong uri ng dispatch sa Swift: vtable para sa class (Dog), objc_msgSend para sa @objc dynamic (Cat) at direct call para sa struct (Cow). Ang mga protocol witness sa existential container ([SoundMaker]) ay nagdaragdag ng overhead. Sa praktika, pinipili ng Swift ang static na dispatch kung saan posible, na nagbibigay ng pagganap na malapit sa C.

Swift Runtime at tulay ng Objective-C

Swift Runtime ay dinisenyo para sa ganap na pagkakatugma sa Objective-C Runtime. Bawat klase ng Swift na nagmamana ng NSObject ay awtomatikong nagrerehistro sa Objective-C Runtime at maaaring tawagin sa pamamagitan ng objc_msgSend. Ang atributong @objc ay ginagawang accessible ang pamamaraan ng Swift mula sa Objective-C. Tulay ng String: ang Swift String ay awtomatikong ibinabridge sa NSString kapag ipinasa sa Objective-C API (toll-free bridging).

ARC: Automatic Reference Counting at pamamahala ng memorya

ARC (Automatic Reference Counting) — sistema ng pamamahala ng memorya sa iOS, na gumagana sa yugto ng kompilasyon. Ang compiler (Clang) ay sumusuri sa lifecycle ng mga bagay at awtomatikong naglalagay ng mga tawag na retain/release/autorelease. Hindi kailangang manu-manong tawagin ng developer ang mga ito — hindi tulad ng Manual Retain-Release (MRR) bago ang iOS 5. Gumagana ang ARC sa antas ng mga bagay ng Objective-C at Swift class, ngunit hindi para sa value types (struct, enum).

Bawat Objective-C na bagay at Swift class ay may bilang ng reference (retain count), na iniimbak sa field na extra_rc sa loob ng non-pointer isa. Sa paglikha ng bagay, retain count = 1. Sa retain, tumataas ang bilang; sa release, bumababa. Kapag ang bilang ay umabot sa 0, ang bagay ay dideallocate sa pamamagitan ng dealloc (Objective-C) o deinit (Swift). Ang ARC ay thread-safe: ang retain/release ay gumagamit ng atomic na operasyon (OSAtomicIncrement32/OSAtomicDecrement32).

Retain cycles — pangunahing problema ng ARC. Kung ang bagay A ay nag-iimbak ng strong reference sa B, at B — strong reference sa A, ang parehong bagay ay hindi kailanman made-deallocate dahil ang kanilang mga bilang ng reference ay hindi magiging zero. Solusyon — mahinang mga reference (__weak sa Objective-C, weak sa Swift) o unowned. Ang mahinang mga reference ay hindi nagpapataas ng retain count at awtomatikong nagiging zero (nil) sa dealokasyon ng bagay.

Pag-debug ng mga retain cycle sa pamamagitan ng Instruments

swift
import Foundation

// Halimbawa ng retain cycle
class Parent {
    var child: Child?
    deinit { print("Parent deallocated") }
}

class Child {
    var parent: Parent?  // strong — lumilikha ng retain cycle!
    deinit { print("Child deallocated") }
}

var parent: Parent? = Parent()
var child: Child? = Child()
parent?.child = child
child?.parent = parent  // siklo: Parent -> Child -> Parent
parent = nil
child = nil
// Ang deinit HINDI tinatawag — pagtagas ng memorya!

// Pag-aayos: weak
class WeakChild {
    weak var parent: Parent?  // weak — hindi nagpapataas ng retain count
    deinit { print("WeakChild deallocated") }
}

// Pag-aayos: unowned (para sa garantisadong haba ng buhay)
class UnownedChild {
    unowned let parent: Parent
    init(parent: Parent) { self.parent = parent }
    deinit { print("UnownedChild deallocated") }
}

// Pagsusuri sa pamamagitan ng Instruments
func profileMemory() {
    // 1. Patakbuhin ang Instruments > Leaks
    // 2. Gawin ang aksyon na lumilikha ng mga bagay
    // 3. Suriin ang Leaks para sa mga tagas
    // 4. Sa Allocations hanapin ang mga bagay na walang dealloc
    for _ in 0..<1000 {
        let p = Parent()
        let c = WeakChild()
        p.child = c as? Child
        // c.parent = p — HINDI idinagdag, weak
    }
}

Halimbawa ng retain cycle sa pagitan ng Parent at Child: parehong may strong reference sa isa't isa, hindi ma-zero ng ARC ang mga bilang. Pag-aayos — weak parent sa Child. Ang weak ay awtomatikong nagiging zero sa dealokasyon ng parent. unowned — para sa mga kaso kung saan ang haba ng buhay ng parent ay garantisadong mas mahaba kaysa sa child (halimbawa, viewController at view). Gamitin ang Instruments > Leaks para sa pag-detect ng mga retain cycle sa maagang yugto.

Autorelease pool

Autorelease pool — mekanismo ng naantalang release para sa mga bagay na nilikha nang walang tahasang pagmamay-ari. Ang @autoreleasepool { } sa Swift at Objective-C ay lumilikha ng pool na pinatuyo sa dulo ng block, na nagpapadala ng release sa bawat bagay sa pool. Kritikal sa mga loop (paglikha ng libu-libong pansamantalang bagay) at sa mga background thread na walang RunLoop. Ang UIKit RunLoop ay awtomatikong pinatuyo ang main autorelease pool sa bawat iteration.

dyld: dynamic na tagapag-load at pagsisimula ng aplikasyon

dyld (dynamic link editor) — tagapag-load ng sistema na responsable para sa pag-load ng mga executable file ng Mach-O at mga kaugnay na dynamic na library (dylib) sa pagsisimula ng iOS application. Ang dyld ay matatagpuan sa /usr/lib/dyld at bahagi ng libSystem. Ang proseso ng pag-load ay may kasamang ilang yugto: pag-parse ng Mach-O, pag-load ng mga dependency (Library Loader, LC_LOAD_DYLIB), relocation ng mga address (ASLR), pagsisimula ng Objective-C Runtime at tawag sa main().

Ang oras ng pagsisimula ng aplikasyon (launch time) ay kritikal na nakadepende sa dyld: mas maraming dynamic na library at Objective-C na klase, mas mahaba ang pre-main time. Inirerekomenda ng Apple na bawasan ang bilang ng mga +load na pamamaraan (naisasagawa bago ang main), palitan ang mga ito ng +initialize (tamad na pagsisimula). Mula noong 2020, gumagamit ang Apple ng prebuilt dyld cache sa iOS: ang mga system library ay na-pre-link sa isang cache, na nagpapabilis ng pag-load.

Pagsukat ng pre-main time

swift
import Foundation

// Pagsukat ng oras ng pagsisimula sa pamamagitan ng DYLD_PRINT_STATISTICS
// Sa Xcode: Edit Scheme > Run > Arguments > Environment Variables
// DYLD_PRINT_STATISTICS = 1
// DYLD_PRINT_STATISTICS_DETAILS = 1

// Programatikong pagsukat ng pre-main time
@main
struct AppMain {
    static func main() {
        let launchStart = CFAbsoluteTimeGetCurrent()

        // Ang UIApplicationMain ay nangyayari dito
        AppDelegate.main()

        let launchEnd = CFAbsoluteTimeGetCurrent()
        let preMainTime = launchEnd - launchStart
        print("Pre-main time: (preMainTime) sec")
    }
}

// Pag-optimize: pagpapalit ng +load ng +initialize
class OptimizedClass {
    // ❌ Ang +load ay isinasagawa bago ang main
    // override class func load() { }

    // ✅ Ang +initialize ay isinasagawa sa unang paggamit
    static let shared = OptimizedClass()
    private init() {
        // Pagsisimula dito
    }
}

// Pag-optimize ng bilang ng dylib
// Ang pagsasama ng static na library ay nagbabawas ng bilang ng LC_LOAD_DYLIB
// Gamitin ang -ObjC flag para sa pag-link lamang ng mga ginamit na Objective-C na klase
// Xcode: Build Settings > Mach-O Type > Static Library

Para sa pagsukat ng pre-main time gamitin ang DYLD_PRINT_STATISTICS sa scheme ng Xcode. Ang output ay magpapakita ng total time, dylib loading time, rebase/bind time, Objective-C setup time at initializer time. Target na halaga: total < 400ms para sa malamig na pagsisimula, < 200ms para sa mainit na pagsisimula. Mga pag-optimize: pagsasama ng mga library, pagpapalit ng +load ng +initialize, pagbawas ng bilang ng mga Objective-C na klase (gamitin ang Swift), minimal na bilang ng mga dynamic na framework.

dsc (dyld shared cache)

dyld shared cache — cache ng mga pre-link na system library sa iOS. Lahat ng system dylib (UIKit, Foundation, CoreGraphics) ay pinagsama sa isang file: /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64. Tinatanggal nito ang pangangailangan na i-load ang bawat system library nang hiwalay — ang dyld ay uma-access sa cache, na makabuluhang nagpapabilis ng pagsisimula. Ang mga aplikasyon na may 10+ dynamic na framework ay nakakaranas ng pinakamalaking pagkaantala dahil ang mga custom na dylib ay hindi bahagi ng dsc.

Mga madalas itanong

Ano ang iOS Runtime at sa anong mga bahagi ito binubuo?

iOS Runtime — kapaligiran ng pagpapatupad ng aplikasyon sa iOS, kabilang ang Objective-C Runtime (libobjc.dylib), Swift Runtime (libswiftCore.dylib), mga framework ng Cocoa Touch, dyld (dynamic na tagapag-load) at ARC (pamamahala ng memorya). Nagbibigay ng message passing para sa Objective-C, static na dispatch para sa Swift, pag-load ng mga file ng Mach-O at awtomatikong pamamahala ng memorya.

Paano naiiba ang Objective-C Runtime sa Swift Runtime?

Objective-C Runtime ay gumagamit ng dynamic na pagbubuklod sa pamamagitan ng objc_msgSend (message passing) na may huling pagbubuklod. Swift Runtime ay gumagamit ng static na dispatch (vtable para sa mga klase, direct call para sa struct) para sa pagganap. Ang @objc dynamic ay nag-activate ng Objective-C Runtime para sa mga klase ng Swift. Ang Swift struct ay walang isa pointer at hindi gumagamit ng retain/release.

Paano gumagana ang ARC sa iOS?

ARC (Automatic Reference Counting) — pamamahala ng memorya sa yugto ng kompilasyon. Ang Clang compiler ay awtomatikong naglalagay ng mga tawag na retain/release. Bawat bagay ay may bilang ng reference, kapag zero ay tinatawag ang dealloc. Ang mga retain cycle (mutual strong references) ay pinipigilan ng weak/unowned references. Gamitin ang Instruments > Leaks para sa pag-detect ng mga tagas.

Ano ang dyld at paano ito nakakaapekto sa pagsisimula ng aplikasyon?

dyld — dynamic na tagapag-load ng mga file ng Mach-O. Nilolo-load ang executable file at lahat ng dependent dylib, nagsasagawa ng relocation (ASLR), sinisimulan ang Objective-C Runtime at tinatawag ang main(). Ang pre-main time ay nakadepende sa bilang ng dylib at mga +load na pamamaraan. Gamitin ang DYLD_PRINT_STATISTICS para sa pagsukat. Pag-optimize: pagsasama ng mga library, pagpapalit ng +load ng +initialize.

Ano ang Method Swizzling at kailan ito gagamitin?

Method Swizzling — teknik ng pagpapalit ng IMP (implementation pointer) ng pamamaraan sa pamamagitan ng Objective-C Runtime class_getInstanceMethod at method_exchangeImplementations. Ginagamit para sa A/B testing, analytics (awtomatikong pagsubaybay ng mga screen) at monitoring. Hindi inirerekomenda sa produksyon nang walang matinding pangangailangan. Sa Swift ay pinalitan ng @objc dynamic + Method Swizzling.

Buod

  • iOS Runtime — kapaligiran ng pagpapatupad ng iOS application, kabilang ang Objective-C Runtime, Swift Runtime, dyld at ARC
  • Objective-C Runtime — message passing (objc_msgSend), isa pointer, swizzling, dynamic na mga klase
  • Swift Runtime — static na dispatch (vtable, direct call), value types, protocol witnesses
  • ARC (Automatic Reference Counting) — awtomatikong pamamahala ng memorya na may retain/release sa yugto ng kompilasyon
  • dyld — dynamic na tagapag-load ng Mach-O na tinutukoy ang bilis ng pagsisimula ng aplikasyon (pre-main time)
  • Retain cycles — pinipigilan ng weak/unowned references; pag-debug sa pamamagitan ng Instruments Leaks
  • Pag-optimize — minimum +load, pagsasama ng dylib, paggamit ng Swift struct para sa value types

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din