深度對比:Objective-C與Swift的RunTime機制與底層原理

1. RunTime簡介

RunTime(運行時)是指程序在運行過程中動態管理類型、對象、方法等的機制。Objective-C?和?Swift?都擁有自己的運行時系統,但設計理念和實現方式有很大不同。理解?RunTime?的底層原理,是掌握?iOS?高級開發的關鍵。

2. Objective-C?RunTime底層原理

2.1 對象結構與isa指針

2.1.1 OC對象的本質

Objective-C?對象在底層以結構體的形式實現,其最核心的成員是 isa 指針。

struct objc_object {Class isa;
};
  • objc_object?是所有?OC?對象的基類結構體,只包含 isa 指針。
  • 每個實例對象的內存布局:isa?指針?+ 父類成員變量 + 本類成員變量(由編譯器自動生成)。
  • Class?實際上是?objc_class?類型,指向類對象。
  • 每個對象通過 isa 指針找到自己的類對象,類對象再通過 isa?指針找到元類對象。

2.1.2 isa指針的優化(isa_t)

isa 指針在?64 位系統下被設計為共用體(union),不僅存儲類對象地址,還包含如是否為?Tagged?Pointer、部分標志位等信息。引用計數等信息通常存儲在 side table 中,只有部分位(如?extra_rc)用于優化。

union isa_t {isa_t() { }isa_t(uintptr_t value) : bits(value) { }Class cls;uintptr_t bits;struct {uintptr_t nonpointer        : 1;uintptr_t has_assoc         : 1;uintptr_t has_cxx_dtor      : 1;uintptr_t shiftcls          : 33;uintptr_t magic             : 6;uintptr_t weakly_referenced : 1;uintptr_t deallocating      : 1;uintptr_t has_sidetable_rc  : 1;uintptr_t extra_rc          : 19;};
};
  • nonpointer:是否為優化過的isa指針
  • shiftcls:類對象地址
  • extra_rc:引用計數
  • has_assoc:是否有關聯對象

Tagged Pointer:對于部分小對象(如小范圍的 NSNumber、NSDate),系統會直接將值編碼在指針中,從而提升性能。

2.1.3 OC對象的內存布局

實際內存布局順序為:

  1. isa指針(對象頭部,8字節/4字節,取決于架構)
  2. 父類的成員變量(從NSObject/父類開始,依次向下排列)
  3. 本類聲明的成員變量(按聲明順序排列)

以下代碼為例:

@interface Animal : NSObject {int age;int height;
}
@end@interface Dog : Animal {int weight;int color;
}
@end

Dog對象的內存布局:

| isa | age?| height?| weight?| color?|

|-----|-------|----------|-----------|--------|

  • isa:指向類對象
  • age、height:Animal父類成員變量
  • weight、color:Dog本類成員變量

這樣設計可以保證子類對象在作為父類對象使用時,父類成員變量的偏移量不變,從而保證繼承的兼容性和對象模型的穩定性。

2.2 類對象與元類對象

2.2.1 類對象(Class)

類對象本質也是一個結構體,定義如下(簡化版):

struct objc_class : objc_object {Class isa;Class super_class;cache_t cache;class_data_bits_t bits;// 下面是bits指向的數據結構(class_rw_t/class_ro_t),用于描述類的詳細信息// 這里只做偽代碼展示struct class_rw_t {uint32_t flags;                // 標志位uint32_t version;              // 版本號const class_ro_t *ro;          // 指向只讀數據method_list_t *methods;        // 方法列表property_list_t *properties;   // 屬性列表protocol_list_t *protocols;    // 協議列表ivar_list_t *ivars;            // 成員變量列表// ... 其他運行時擴展信息};struct class_ro_t {uint32_t flags;                // 標志位uint32_t instanceStart;        // 實例對象起始偏移uint32_t instanceSize;         // 實例對象大小const char *name;              // 類名method_list_t *methods;        // 方法列表property_list_t *properties;   // 屬性列表protocol_list_t *protocols;    // 協議列表ivar_list_t *ivars;            // 成員變量列表// ... 其他只讀信息};
};
  • isa:指向元類對象
  • super_class:指向父類對象
  • cache:方法緩存
  • class_data_bits_t:存儲方法列表、屬性列表、協議列表等

2.2.2 元類對象(Meta-Class)

  • 元類對象用于存儲類方法的實現,本質上類方法就是元類的實例方法。
  • 元類的isa指向根元類(NSObject的Meta-Class)
  • 元類的super_class指向父類的元類
  • 根元類的isa指針指向自己

2.2.3 內存結構圖

  • 類對象和元類對象本質上都是objc_class結構體
  • 類對象存儲實例方法,元類對象存儲類方法

2.3 方法緩存與方法列表

2.3.1 方法緩存(cache_t)

每個類對象都有一個方法緩存cache,結構如下:

struct cache_t {struct bucket_t *_buckets;mask_t _mask;mask_t _occupied;
};
  • _buckets:哈希表,存儲 SEL(方法選擇子)和 IMP(實現指針)的映射關系。
  • _mask、_occupied:用于哈希沖突處理

作用:加速方法查找,避免每次都遍歷方法列表。

2.3.2 方法列表

類對象中有方法列表,存儲所有實例方法:

struct method_t {SEL name;      // 方法名const char *types; // 方法類型編碼IMP imp;       // 方法實現指針
};
  • 方法查找順序:先查緩存,再查方法列表,最后查父類

2.4 成員變量與屬性

  • 成員變量(Ivar)

在類對象的?ivar_list?中,保存的是所有成員變量的描述信息(如名字、類型、偏移量等),而成員變量的實際值是存儲在每個實例對象的內存空間中(緊跟在 isa 指針之后,按照繼承鏈和聲明順序排列)。

    • 屬性(Property)

    屬性信息存儲在類對象的?property_list?中,僅用于描述屬性的名稱、類型、特性等。屬性通常會自動合成一個對應的成員變量(如?name),成員變量的實際值存儲在實例對象中。

    // 成員變量描述結構體
    struct ivar_t {int32_t *offset;      // 偏移量(成員變量在實例對象內存中的位置)const char *name;     // 成員變量名const char *type;     // 類型編碼// ... 其他信息
    };// 成員變量列表
    struct ivar_list_t {uint32_t count;       // 成員變量數量ivar_t ivars[];       // 成員變量數組
    };// 屬性描述結構體
    struct property_t {const char *name;     // 屬性名const char *attributes; // 屬性特性字符串(如T@"NSString",C,N,V_name等)// ... 其他信息
    };// 屬性列表
    struct property_list_t {uint32_t count;         // 屬性數量property_t properties[];// 屬性數組
    };
    

    3. Objective-C消息機制與方法查找——RunTime的靈魂

    3.1 objc_msgSend流程

    Objective-C?的方法調用本質上是“向對象發送消息”,而?objc_msgSend?就是消息發送的核心函數。理解其底層流程,是掌握?RunTime?的關鍵。

    1. 空對象判斷(Nil?Check)

    • 首先判斷消息接收者(對象指針)是否為 nil。
    • 如果是?nil,objc_msgSend?直接返回?0,不做任何操作(這也是 OC?調用?nil 對象不會崩潰的原因)。

    2. 獲取類對象(Class?Lookup)

    • 通過對象頭部的?isa 指針,獲取當前對象的類對象(Class)。

    3. 方法緩存查找(Cache Lookup)

    • 優先在類對象的緩存(cache_t)中查找方法實現(IMP)。
    • 如果緩存命中,直接跳轉到對應的?IMP 執行,速度極快。

    4. 方法列表查找(Method List Lookup)

    • 如果緩存未命中,則遍歷類對象的方法列表(method_list_t),查找與?SEL(方法選擇子)匹配的方法。
    • 找到后,將?SEL?和 IMP?加入緩存,便于下次快速查找。

    5. 父類鏈查找(Superclass Lookup)

    • 如果當前類的方法列表中仍未找到目標方法,則順著?super_class?指針,遞歸查找父類的方法緩存和方法列表,直到?NSObject?為止。

    6. 動態方法解析(Dynamic?Method?Resolution)

    • 如果在整個繼承鏈上都找不到目標方法,RunTime?會嘗試動態方法解析。
    • 通過調用?+resolveInstanceMethod:?或?+resolveClassMethod:,允許開發者動態添加方法實現。
    • 如果在回調中通過?class_addMethod?成功添加了方法,RunTime 會重新走一次方法查找流程。

    7. 消息轉發機制(Message Forwarding)

    • 如果動態方法解析仍未能處理該消息,進入消息轉發階段:
    • 首先調用?-forwardingTargetForSelector:,允許指定其他對象響應該消息。
    • 如果還未處理,則調用?-methodSignatureForSelector:?和?-forwardInvocation:,開發者可自定義消息處理邏輯。

    8. 拋出異常(Unrecognized?Selector)

    • 如果所有機制都未能處理該消息,RunTime?最終會拋出?unrecognized selector sent?to?instance?異常,導致程序崩潰。

    3.2?消息轉發三步曲

    當對象接收到一個未實現的方法調用時,RunTime?會依次經歷以下步驟:

    1. 動態方法解析(resolveInstanceMethod:、resolveClassMethod:)
    2. 快速消息轉發(forwardingTargetForSelector:)
    3. 完整消息轉發(methodSignatureForSelector:?&?forwardInvocation:)

    下面我們逐步拆解每一步的底層實現。

    3.2.1?動態方法解析(resolveInstanceMethod、resolveClassMethod)

    底層原理:

    當實例方法找不到時,RunTime 會調用?+resolveInstanceMethod:;類方法找不到時,調用?+resolveClassMethod:。你可以在這里通過?class_addMethod?動態添加方法。

    代碼示例:

    // 動態添加實例方法
    + (BOOL)resolveInstanceMethod:(SEL)sel {if (sel == @selector(test)) {class_addMethod(self, sel, (IMP)testIMP, "v@:");return YES;}return [super resolveInstanceMethod:sel];
    }// 動態添加類方法
    + (BOOL)resolveClassMethod:(SEL)sel {if (sel == @selector(testClassMethod)) {Class metaClass = object_getClass(self); // 獲取元類class_addMethod(metaClass, sel, (IMP)testClassMethodIMP, "v@:");return YES;}return [super resolveClassMethod:sel];
    }
    • 如果返回 YES,RunTime?會重新查找方法并執行。
    • 如果返回?NO?或未處理,進入下一步。

    3.2.2?快速消息轉發(forwardingTargetForSelector:)

    底層原理:

    如果動態方法解析未能處理,RunTime 會調用實例方法?-forwardingTargetForSelector:。你可以返回一個“備選接收者”,RunTime 會將消息直接轉發給該對象。如果返回?nil,進入完整消息轉發。

    代碼示例:

    - (id)forwardingTargetForSelector:(SEL)aSelector {if (aSelector == @selector(test)) {return anotherObj; // 轉發給 anotherObj}return [super forwardingTargetForSelector:aSelector];
    }

      3.2.3?獲取方法簽名(methodSignatureForSelector:)

      底層原理:

      如果快速轉發未處理,RunTime 會調用?-methodSignatureForSelector:,詢問你“這個 SEL 對應的方法簽名是什么?”你需要返回一個 NSMethodSignature 對象,描述方法的參數和返回值類型。如果返回 nil,RunTime?會直接拋出異常。

      代碼示例:

      - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {if (aSelector == @selector(test:)) {return [NSMethodSignature signatureWithObjCTypes:"v@:@"];}return [super methodSignatureForSelector:aSelector];
      }

      3.2.4?自定義消息處理(forwardInvocation:)

      底層原理:

      RunTime 會根據方法簽名創建一個 NSInvocation 對象,封裝原始的消息調用。然后調用?-forwardInvocation:,你可以在這里自定義如何處理這個消息,比如轉發給其他對象、修改參數、記錄日志等。如果你沒有處理,調用?[super forwardInvocation:],最終會拋出異常。

      代碼示例:

      - (void)forwardInvocation:(NSInvocation *)anInvocation {if ([anotherObj respondsToSelector:anInvocation.selector]) {[anInvocation invokeWithTarget:anotherObj];} else {[super forwardInvocation:anInvocation];}
      }

      3.3 拋出異常(unrecognized selector)

      1. 底層原理

      如果上述所有機制都未能處理該消息,RunTime?會調用?doesNotRecognizeSelector:,最終拋出?unrecognized selector sent to instance?異常,導致程序崩潰。

      2. 異常信息解讀

      當出現此異常時,Xcode控制臺會輸出類似如下信息:

      Terminating app due to uncaught exception 'NSInvalidArgumentException', 
      reason: '-[MyClass test]: unrecognized selector sent to instance 0x12345678'
      • MyClass:出錯的類名
      • test:未識別的方法名
      • 0x12345678:對象內存地址

      4. Swift RunTime機制深度剖析

      4.1 Swift對象模型:值類型與引用類型的本質

      4.1.1 值類型與引用類型的區別

      在Swift中,對象主要分為兩種類型:值類型和引用類型。這兩種類型在內存管理和使用方式上有著本質的區別:

      • 值類型:包括struct和enum,數據直接存儲在變量本身,通常在棧上分配,內存布局緊湊,訪問效率高。賦值時進行值拷貝。
      • 引用類型:主要指class,數據存儲在堆上,變量保存的是指向對象的指針。支持繼承和多態,賦值時傳遞引用。

      4.1.2 Swift類對象的內存結構

      Swift的類對象采用了現代化的內存布局設計,其結構如下:

      | Metadata指針 | 屬性1 | 屬性2 | ... |
      • Metadata指針:指向類型的元數據,類似于Objective-C的isa指針,但包含更豐富的信息
      • 屬性區:按順序存儲對象的所有屬性值

      4.1.3?繼承NSObject的Swift類的內存結構

      繼承NSObject的Swift類同時具有Swift和Objective-C的特征

      以下代碼為例:

      class MyClass: NSObject {var property1: Intvar property2: String
      }

        其內存布局如下所示:

        +------------------+------------------+------------------+------------------+
        |   isa指針(OC)    | Metadata指針(Swift) |    property1    |    property2    |
        +------------------+------------------+------------------+------------------+
        • 對象頭部包含兩個指針: Objective-C的isa指針和Swift的Metadata指針。
        • 屬性按照Swift的內存布局規則排列。
        • 方法根據是否@objc決定存儲位置,objc方法:存儲在Objective-C的class_rw_t中,非@objc方法:存儲在Swift的虛表中。

        這種混合結構讓繼承NSObject的Swift類既能保持Swift的高效,又能與Objective-C無縫交互。

        4.1.4?Metadata元數據詳解

        Metadata是Swift類型系統的核心,它記錄了類型在運行時的所有關鍵信息。以類(Class)為例,其簡化結構如下:

        以類(Class)為例,簡化結構如下:

        struct ClassMetadata {void *kind;           // 類型標識(區分class/struct/enum等)void *superclass;     // 父類的Metadata指針void *cacheData;      // 方法緩存(加速查找)void *data;           // 指向更詳細的類型描述// ... 其他字段
        };
        Metadata采用分層設計:基礎信息在前,詳細信息通過指針層層遞進。

        1. 基礎層:包含類型標識、父類信息等基本信息

        2.?擴展層:過data指針指向更詳細的信息,包括:

        • vtable:虛函數表,存儲可重寫方法的實現指針
        • witness table:協議表,存儲協議方法的實現
        • 屬性描述:屬性名、類型、偏移量等
        • 泛型信息:泛型參數的類型描述

        4.2 Swift方法調用機制:靜態與動態的平衡

        4.2.1 靜態派發:Swift的默認選擇

        Swift默認采用靜態派發機制,這意味著:

        • 方法調用在編譯期就確定了調用地址。調用時無需查找,直接跳轉
        • 適用于struct、final class、private方法等場景
        • 執行效率高,接近C語言的函數調用

        4.2.2 動態派發:特定場景的選擇

        在以下情況下,Swift會采用動態派發機制:

        • 被dynamic修飾的方法
        • 遵循@objc協議的方法
        • 繼承自NSObject的類中的方法
        • 協議的可選方法

        動態派發通過vtable(虛函數表)或witness table(協議表)實現:

        +-------------------+
        | 方法1的指針(IMP) |
        | 方法2的指針(IMP) |
        | ...               |
        +-------------------+

        4.2.3 方法查找流程對比

        • 靜態派發:編譯期確定方法地址,直接調用方法實現,無需運行時查找。
        • 動態派發:運行時查找vtable/witness table,獲取方法實現指針,調用方法實現。

        4.2.4?與Objective-C的對比

        • OC:所有方法調用都走objc_msgSend,完全動態派發,靈活性高,但性能開銷大。
        • Swift:優先使用靜態派發,僅在必要時使用動態派發,性能更優,但動態性受限。

        4.3 Swift的反射與元編程能力

        4.3.1 Mirror反射API

        Swift提供了Mirror類型用于運行時反射,可以獲取對象的屬性名、屬性值、類型等信息。

        let mirror = Mirror(reflecting: someObject)
        for child in mirror.children {print("屬性名: \(child.label), 屬性值: \(child.value)")
        }
        • 只能讀取對象信息,不能修改。
        • 支持獲取屬性名、屬性值、類型等信息,使用簡單,但功能有限。

        4.3.2 Swift RunTime的局限性

        • 無法動態添加/替換方法:沒有公開的RunTime C API
        • 類型信息有限:大部分類型信息在編譯期丟失
        • 元編程能力弱:不支持元類、動態創建類等高級特性

        4.3.3?Swift RunTime的設計哲學與優化

        • 類型安全:所有類型信息盡量在編譯期確定,避免運行時錯誤
        • 極致性能:靜態派發、緊湊內存布局、去虛表等優化
        • 安全性高:避免了OC RunTime帶來的諸多安全隱患

        總結一句話:

        Swift 的 RunTime 機制以犧牲部分動態性為代價,換來了更高的類型安全和運行效率。

        5. Objective-C與Swift RunTime機制對比

        5.1 核心機制對比

        Objective-C RunTimeSwift RunTime
        對象頭部isa指針,部分信息存side tableMetadata指針,引用計數直接存對象頭部
        方法派發動態派發(objc_msgSend),全部運行時查找靜態派發為主,動態派發僅限特殊場景
        動態性極強,支持動態添加/替換方法、類、屬性等較弱,類型和方法多在編譯期確定
        反射能力強大,支持完整反射和元編程Mirror API有限,無法動態修改類型結構
        內存布局對象頭部+成員變量,side table存擴展信息Metadata指針+屬性區,布局緊湊
        弱引用全局weak表,side table輔助全局weak表,直接與對象頭部配合
        關聯對象支持(依賴side table)不支持(標準庫無此機制)
        性能動態性帶來一定性能損耗靜態派發、內存優化,性能極高
        安全性動態性強但易出錯類型安全,編譯期檢查,運行時更安全
        混編支持與C/Swift無縫混編與OC混編需繼承NSObject,部分特性受限

        5.2 方法派發機制

        • Objective-C 所有方法調用都通過objc_msgSend來實現,也就是每次調用方法時,系統都會在運行時查找方法的具體實現。這種方式非常靈活,可以在運行時動態替換方法,但也帶來了一定的性能損耗。

        • Swift采用以靜態派發為主的混合派發機制。大多數方法在編譯期就確定了實現位置,只有少數特殊情況(如被dynamic修飾的方法、遵循@objc協議的方法、協議的可選方法、繼承自NSObject的類的方法)才會使用動態派發。動態派發通過vtable或witness table實現,雖然限制了動態性,但大大提升了性能。

        5.3 動態性與反射

        • Objective-C具備極強的動態性。開發者可以在運行時動態添加或替換方法、創建新類、修改類結構,還可以通過完整的反射API查詢和操作類型信息。這些特性使其非常適合實現AOP、熱修復等高級功能。例如,可以通過class_addMethod動態添加方法,通過method_exchangeImplementations交換方法實現。

        • Swift的動態性相對較弱。大多數類型信息在編譯期就已確定,運行時修改能力有限。雖然提供了Mirror API用于查看對象屬性和類型信息,但無法動態修改類型結構。這種設計雖然限制了某些高級特性的實現,但更適合類型安全的業務開發。例如,可以通過Mirror(reflecting: object)查看對象屬性。

        5.4 內存布局與side table

        • Objective-C的對象內存布局包含isa指針(8字節)和按聲明順序排列的成員變量。擴展信息(如引用計數、弱引用、關聯對象、方法緩存等)存儲在side table中。這種設計雖然減少了對象本身的內存占用,但訪問這些信息需要額外查找side table,增加了訪問成本。

        • Swift的對象內存布局包含Metadata指針和按聲明順序排列的屬性。引用計數直接存儲在對象頭部,弱引用與對象頭部配合,沒有公開的side table機制。這種設計雖然增加了對象本身的大小,但減少了訪問開銷,整體內存布局更緊湊高效。

        5.5 實際開發影響

        • 在框架開發中,Objective-C更適合需要高度動態性的場景,如AOP實現、熱修復系統、插件化架構、動態代理、KVO/KVC等。可以通過減少消息發送、緩存方法實現、優化內存布局、合理使用side table等方式優化性能。

        • Swift更適合高性能業務邏輯、類型安全API、并發編程、函數式編程等場景。可以通過利用靜態派發、優化值類型使用、減少動態派發、優化內存布局等方式提升性能。在混編開發中,需要明確邊界、合理分工、注意性能、統一規范,根據具體需求選擇合適的語言或混編方案。

        6. RunTime的實際應用場景與代碼示例

        6.1 Objective-C?RunTime常見用法

        6.1.1 方法交換(Method?Swizzling)

        場景:無侵入埋點、AOP、日志等。

        示例:統計所有UIViewController的viewDidLoad調用。

        #import <objc/runtime.h>@implementation UIViewController (Swizzling)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Method original = class_getInstanceMethod(self, @selector(viewDidLoad));Method swizzled = class_getInstanceMethod(self, @selector(swizzled_viewDidLoad));method_exchangeImplementations(original, swizzled);});
        }- (void)swizzled_viewDidLoad {NSLog(@"%@ did load", NSStringFromClass([self class]));[self swizzled_viewDidLoad]; // 實際調用原viewDidLoad
        }@end

        6.1.2 動態添加屬性(關聯對象)

        場景:為Category動態添加屬性。

        #import <objc/runtime.h>static const void *kNameKey = &kNameKey;@interface Person : NSObject
        @end@implementation Person
        @end@interface Person (Category)
        @property (nonatomic, strong) NSString *name;
        @end@implementation Person (Category)- (void)setName:(NSString *)name {objc_setAssociatedObject(self, kNameKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        - (NSString *)name {return objc_getAssociatedObject(self, kNameKey);
        }@end

        6.1.3 自動歸檔與解檔

        場景:自動實現NSCoding協議,無需手寫每個屬性。

        #import <objc/runtime.h>@implementation Person- (void)encodeWithCoder:(NSCoder *)coder {unsigned int count = 0;Ivar *ivars = class_copyIvarList([self class], &count);for (int i = 0; i < count; i++) {Ivar ivar = ivars[i];NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];id value = [self valueForKey:key];[coder encodeObject:value forKey:key];}free(ivars);
        }- (instancetype)initWithCoder:(NSCoder *)coder {if (self = [super init]) {unsigned int count = 0;Ivar *ivars = class_copyIvarList([self class], &count);for (int i = 0; i < count; i++) {Ivar ivar = ivars[i];NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];id value = [coder decodeObjectForKey:key];[self setValue:value forKey:key];}free(ivars);}return self;
        }@end

        6.1.4 消息轉發機制

        場景:多重代理、消息中轉、容錯處理。

        // 快速消息轉發
        - (id)forwardingTargetForSelector:(SEL)aSelector {if (aSelector == @selector(testMethod)) {return self.anotherObject;}return [super forwardingTargetForSelector:aSelector];
        }// 完整消息轉發
        - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {if (aSelector == @selector(testMethod)) {return [NSMethodSignature signatureWithObjCTypes:"v@:"];}return [super methodSignatureForSelector:aSelector];
        }- (void)forwardInvocation:(NSInvocation *)anInvocation {if ([self.anotherObject respondsToSelector:anInvocation.selector]) {[anInvocation invokeWithTarget:self.anotherObject];} else {[super forwardInvocation:anInvocation];}
        }

        6.2 Swift RunTime常見用法

        6.2.1 Mirror反射

        場景:調試、日志、自動打印對象屬性。

        struct Person {var name: Stringvar age: Int
        }let p = Person(name: "Tom", age: 18)
        let mirror = Mirror(reflecting: p)
        for child in mirror.children {print("屬性名: \(child.label ?? ""), 屬性值: \(child.value)")
        }
        // 輸出:
        // 屬性名: name, 屬性值: Tom
        // 屬性名: age, 屬性值: 18

        6.2.2 動態派發與@objc

        場景:需要與OC交互、KVO、KVC、消息轉發等。

        class Animal: NSObject {@objc dynamic func run() {print("Animal run")}
        }class Dog: Animal {override func run() {print("Dog run")}
        }let a: Animal = Dog()
        a.run() // 輸出 Dog run,走動態派發

        總結

        RunTime(運行時)是iOS開發的核心機制,主要指程序在運行過程中動態管理類型、對象、方法等的能力。Objective-C的RunTime極為強大,支持動態派發、方法交換、動態添加屬性、消息轉發等,底層通過isa指針、類對象、元類對象、方法緩存等結構實現,所有方法調用都走objc_msgSend,具備極高的靈活性和反射能力,適合AOP、熱修復等高級玩法。Swift的RunTime則以類型安全和高性能為主,大部分方法靜態派發,只有特殊場景才動態查找,反射能力有限,無法動態修改類型結構。兩者對比,OC更動態、靈活,Swift更安全、高效。實際開發中,OC適合底層框架和需要動態性的場景,Swift則適合業務開發和性能敏感場合。理解RunTime原理,有助于開發者寫出更高效、靈活和安全的iOS代碼。


        如果覺得本文對你有幫助,歡迎點贊、收藏、關注我,后續會持續分享更多?iOS?底層原理與實戰經驗

        本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
        如若轉載,請注明出處:http://www.pswp.cn/web/77564.shtml
        繁體地址,請注明出處:http://hk.pswp.cn/web/77564.shtml
        英文地址,請注明出處:http://en.pswp.cn/web/77564.shtml

        如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

        相關文章

        使用手機錄制rosbag包

        文章目錄 簡介錄制工具錄制步驟錄制設置設置IMU錄制頻率設置相機分辨率拍照模式錄制模式數據制作獲取數據數據轉為rosbag查看rosbag簡介 ROS數據包(rosbag)是ROS系統中用于記錄和回放傳感器數據的重要工具,通常用于算法調試、系統測試和數據采集。傳統上,rosbag依賴于ROS環…

        淺談PCB傳輸線(一)

        前言&#xff1a;淺談傳輸線的類型&#xff0c;以及傳輸線的一些行為特性。 1.傳輸線的種類 2.互連線被視為傳輸線的場景 3.傳輸線的行為特性*** 1.傳輸線的種類 PCB 中的信號傳輸線通常有兩種基本類型: 微帶線和帶狀線。此外&#xff0c;還有第三種類型–共面線(沒有參考平面…

        【angular19】入門基礎教程(一):項目的搭建與啟動

        angular現在發展的越來越能完善了&#xff0c;在vue和react的強勢競爭下&#xff0c;它迎來了自己的巨大變革。項目工程化越來越好&#xff0c;也開始擁抱了vite這種高效的構建方式。所以&#xff0c;我們有必要來學習這么一個框架了。 項目實現效果 nodejs環境 Node.js - v^…

        在前端應用領域驅動設計(DDD):必要性、挑戰與實踐指南

        引言 領域驅動設計&#xff08;Domain-Driven Design&#xff0c;簡稱 DDD&#xff09;起源于后端復雜業務系統建模領域&#xff0c;是 Eric Evans 在 2003 年提出的一套理論體系。近年來&#xff0c;隨著前端工程化與業務復雜度的持續提升&#xff0c;"前端也要 DDD&quo…

        一文了解 模型上下文協議(MCP)

        MCP&#xff08;Model Context Protocol&#xff0c;模型上下文協議&#xff09;是由Anthropic公司于2024年11月推出的一項開放標準協議&#xff0c;旨在解決大型語言模型&#xff08;LLM&#xff09;與外部數據源和工具之間的通信問題。其核心目標是通過提供一個標準化的接口&…

        面向全球的行業開源情報體系建設方法論——以易海聚實戰經驗為例

        在全球數字化轉型加速的背景下&#xff0c;如何精準鎖定目標領域的關鍵信息源&#xff0c;構建可持續迭代的情報網絡&#xff0c;已成為企業戰略決策的核心能力。深圳易海聚信息技術有限公司&#xff08;以下簡稱“易海聚”&#xff09;深耕開源情報領域十余年&#xff0c;其自…

        UDP協議詳解+代碼演示

        1、UDP協議基礎 1. UDP是什么&#xff1f; UDP&#xff08;User Datagram Protocol&#xff0c;用戶數據報協議&#xff09;是傳輸層的核心協議之一&#xff0c;與TCP并列。它的主要特點是&#xff1a;???? 無連接&#xff1a;通信前不需要建立連接&#xff08;知道對端的…

        基于大模型的膽總管結石全流程預測與臨床應用研究報告

        目錄 一、引言 1.1 研究背景 1.2 研究目的與意義 1.3 研究方法和創新點 二、大模型在膽總管結石預測中的應用原理 2.1 大模型概述 2.2 模型構建的數據來源與處理 2.3 模型訓練與優化 三、術前預測與準備 3.1 術前膽總管結石存在的預測 3.2 基于預測結果的術前檢查方…

        Windows避坑部署SkyworkAI/SkyReels-V2昆侖萬維電影生成模型

        #工作記錄 前言 SkyworkAI/SkyReels-V2 是由昆侖萬維開源的全球首個無限時長電影生成模型&#xff0c;基于擴散強迫框架結合多模態大語言模型、強化學習等技術&#xff0c;支持文本到視頻、圖像到視頻等多種生成方式 開源項目地址&#xff1a; SkyworkAI/SkyReels-V2&#x…

        iVX 圖形化編程如何改寫后端開發新范式

        在數字化轉型加速推進的當下&#xff0c;企業對后端系統的需求呈現爆發式增長。Gartner 最新報告指出&#xff0c;2025 年全球企業平均需完成 300 定制化應用開發&#xff0c;而傳統編碼模式下&#xff0c;單個項目平均交付周期長達 6 - 8 個月。與此同時&#xff0c;Redis、K…

        策略模式:靈活的算法封裝與切換

        策略模式是一種行為型設計模式&#xff0c;它將一組算法封裝成獨立的類&#xff0c;使它們可以相互替換。策略模式讓算法的變化獨立于使用算法的客戶端。本文將以一個收銀系統為例&#xff0c;詳細介紹策略模式的實現和應用。 什么是策略模式&#xff1f; 策略模式定義了算法…

        第十四章-PHP與HTTP協議

        第十四章-PHP與HTTP協議 一&#xff0c;HTTP 協議詳解 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是互聯網上應用最廣泛的協議之一&#xff0c;用于客戶端&#xff08;如瀏覽器&#xff09;與服務器之間的通信。它是 Web 技術的基石…

        刀客獨家 | 潘勝接管百度移動生態市場部

        一、 據刀客doc向獨家信源確認&#xff0c;百度移動生態事業群&#xff08;MEG&#xff09;市場部日前完成重要人事調整&#xff1a;潘勝已經接任市場負責人。 此前&#xff0c;根據雷鋒網3月底的報道&#xff0c;百度云渠道生態總經理陳之若離職&#xff0c;原移動生態事業群…

        Springoot、Flowable快速學習

        應用背景&#xff1a; 公司打算做個考勤系統&#xff0c;涉及到請假、補卡之類的流程審批。想到了工作流&#xff0c;gitee、github上看了下開源的&#xff0c;有自研的和常見的Flowable?、Activiti?。首先放棄自研的&#xff0c;考慮到成熟度、社區生態&#xff0c;最后選擇…

        關于 【Spring Boot Configuration Annotation Processor 未配置問題】 的詳細分析、解決方案及代碼示例

        以下是關于 Spring Boot Configuration Annotation Processor 未配置問題 的詳細分析、解決方案及代碼示例&#xff1a; 1. 問題描述 當使用 Spring Boot 的配置注解&#xff08;如 ConfigurationProperties、Value、ConditionalOnProperty 等&#xff09;時&#xff0c;若未…

        Spring系列四:AOP切面編程 第一部分

        AOP切面編程 &#x1f497;AOP-官方文檔&#x1f35d;AOP 講解&#x1f35d;AOP APIs &#x1f497;動態代理&#x1f35d;初探動態代理&#x1f35d;動態代理深入&#x1f35d;AOP問題提出&#x1f4d7;使用土方法解決&#x1f4d7; 對土方法解耦-開發最簡單的AOP類&#x1f4…

        【云計算】云計算中IaaS、PaaS、SaaS介紹

        0 隨著云計算、大數據、人工智能發展迅速,布局“云”已經是互聯網企業共識。云計算的服務類型分為三種,分別為IaaS、PaaS、SaaS,這三個分別是什么意思,今天做一個簡單的介紹和了解。 一、云計算 云計算是用戶需求通過Internet獲取計算資源,把計算資源包裝成服務,提供給…

        使用HYPRE庫并行裝配IJ稀疏矩陣指南: 矩陣預分配和重復利用

        使用HYPRE庫并行裝配IJ稀疏矩陣指南 HYPRE是一個流行的并行求解器庫&#xff0c;特別適合大規模稀疏線性系統的求解。下面介紹如何并行裝配IJ格式的稀疏矩陣&#xff0c;包括預先分配矩陣空間和循環使用。 1. 初始化矩陣 首先需要創建并初始化一個IJ矩陣&#xff1a; #incl…

        目標跟蹤最新文章閱讀列表

        AAAI2025 TrackFormer: Multi-Object Tracking with Transformers 論文:https://arxiv.org/abs/2101.02702 代碼:https://github.com/timmeinhardt/trackformer AAAI2025 SUTrack 單目標跟蹤 論文:https://pan.baidu.com/s/10cR4tQt3lSH5V2RNf7-3gg?pwd=pks2 代碼:htt…

        分布式GPU上計算長向量模的方法

        分布式GPU上計算長向量模的方法 當向量分布在多個GPU卡上時&#xff0c;計算向量模(2-范數)需要以下步驟&#xff1a; 在每個GPU上計算本地數據的平方和跨GPU通信匯總所有平方和在根GPU上計算總和的平方根 實現方法 下面是一個完整的CUDA示例代碼&#xff0c;使用NCCL進行多…