• OC和Swift的区别,发送消息和执行方法的区别


    Objective-C 和 Swift 中,方法调用的机制存在显著的区别,具体体现在消息传递和方法调用上。以下是关于这两种机制的详细说明:

    Objective-C:发送消息

    消息传递机制

    Objective-C 使用消息传递(Message Passing)机制来调用方法。这意味着在运行时,方法调用被转化为发送消息给对象。在编译时,编译器不会直接确定调用哪个方法,而是在运行时查找对应的实现。

    [object doSomething];
    

    消息传递的细节
    • 动态性:在运行时确定方法的实现,这使得 Objective-C 非常灵活,可以实现方法交换、动态添加方法等高级特性。
    • 运行时库:Objective-C 有一个强大的运行时库(Runtime Library),负责查找方法的实现、处理消息传递等。
    1. // 发送消息的底层实现
    2. objc_msgSend(object, @selector(doSomething));

    优点
    • 灵活:可以在运行时动态改变对象的行为。
    • 动态绑定:可以实现更复杂的设计模式,如代理、观察者模式。
    缺点
    • 性能开销:由于在运行时查找方法实现,性能上有一定的开销。
    • 类型安全:由于动态性,编译时类型检查较弱,可能导致运行时错误。

    Swift:方法调用

    方法调用机制

    Swift 使用静态绑定(Static Dispatch)和动态绑定(Dynamic Dispatch)两种方式来调用方法。默认情况下,Swift 使用静态绑定,这意味着在编译时确定方法的实现,直接调用方法地址。

    object.doSomething()
    

    方法调用的细节
    • 静态绑定:编译时确定方法的实现,直接调用方法地址,性能更高。        
      • 非类方法:如结构体和枚举的方法。
      • 没有被标记为 @objc 的类方法
      • final 方法:被标记为 final 的方法,不能被子类重写。
    • 动态绑定:通过使用 @objc 关键字或协议,可以实现类似于 Objective-C 的动态绑定。
    1. // 静态绑定
    2. class MyClass {
    3. func doSomething() {
    4. print("Doing something")
    5. }
    6. }
    7. let object = MyClass()
    8. object.doSomething()

    1. // 动态绑定
    2. class MyClass: NSObject {
    3. @objc func doSomething() {
    4. print("Doing something")
    5. }
    6. }
    7. let object = MyClass()
    8. object.perform(#selector(MyClass.doSomething))

    优点
    • 性能高:默认使用静态绑定,方法调用速度快。
    • 类型安全:编译时进行类型检查,减少运行时错误。
    缺点
    • 灵活性:相比 Objective-C,动态性较弱,但可以通过 @objc 和 dynamic 关键字实现动态特性。

    对比总结

    特性Objective-CSwift
    方法调用方式消息传递(Message Passing)静态绑定(Static Dispatch)
    动态绑定(Dynamic Dispatch)
    灵活性高:运行时确定方法实现低:默认编译时确定方法实现
    性能较低:运行时查找方法实现有开销较高:编译时确定方法实现
    类型安全较低:编译时检查较弱较高:编译时类型检查
    实现动态特性简单:原生支持复杂:需要使用 @objc 和 dynamic 关键字
    运行时特性强大:丰富的运行时库支持较弱:但可以通过 @objc 和运行时特性扩展
    常见用途动态代理、方法交换、运行时修改行为高性能方法调用、类型安全编程

    具体应用场景

    • Objective-C 更适合那些需要大量动态特性、运行时行为修改的场景,如动态代理、方法交换、运行时添加方法等。
    • Swift 更适合那些需要高性能、类型安全的场景,如大部分日常应用开发、需要高效执行的代码路径等。如果需要动态特性,可以通过 @objc 和 dynamic 关键字来实现。

    代码示例

    Objective-C 消息传递
    1. #import
    2. @interface MyClass : NSObject
    3. - (void)doSomething;
    4. @end
    5. @implementation MyClass
    6. - (void)doSomething {
    7. NSLog(@"Doing something in Objective-C");
    8. }
    9. @end
    10. int main(int argc, const char * argv[]) {
    11. @autoreleasepool {
    12. MyClass *object = [[MyClass alloc] init];
    13. [object doSomething]; // 消息传递
    14. }
    15. return 0;
    16. }

    Swift 方法调用
    1. import Foundation
    2. class MyClass {
    3. func doSomething() {
    4. print("Doing something in Swift")
    5. }
    6. }
    7. let object = MyClass()
    8. object.doSomething() // 静态绑定

    Swift 动态绑定
    1. import Foundation
    2. class MyClass: NSObject {
    3. @objc func doSomething() {
    4. print("Doing something in Swift with dynamic dispatch")
    5. }
    6. }
    7. let object = MyClass()
    8. object.perform(#selector(MyClass.doSomething)) // 动态绑定

    通过这些代码示例,可以清晰地看到 Objective-C 和 Swift 在方法调用机制上的区别。理解这些区别,将有助于开发者在不同的场景下选择合适的语言和方法调用方式。

    Swift 的方法调用机制主要分为静态绑定和动态绑定:

    • 静态绑定:在编译时确定方法实现,性能较高,适用于结构体、枚举和 final 方法。
    • 动态绑定:在运行时通过虚方法表或 Objective-C 运行时确定方法实现,适用于类的继承层次和需要动态特性的场景。

    理解这些机制,有助于编写高效且健壮的 Swift 代码,并在需要时合理使用动态特性。

    详细说明

    Swift 的方法调用机制主要通过静态绑定(Static Dispatch)和动态绑定(Dynamic Dispatch)来实现。了解这些机制的原理,有助于编写高效且健壮的 Swift 代码。以下是对 Swift 方法调用原理的详细解释:

    1. 静态绑定(Static Dispatch)

    静态绑定也称为直接调用(Direct Dispatch),在编译时就确定了方法的具体实现,并直接调用方法地址。静态绑定通常用于以下情况:

    • 非类方法:如结构体和枚举的方法。
    • 没有被标记为 @objc 的类方法
    • final 方法:被标记为 final 的方法,不能被子类重写。
    示例
    1. struct MyStruct {
    2. func doSomething() {
    3. print("Doing something")
    4. }
    5. }
    6. let myStruct = MyStruct()
    7. myStruct.doSomething() // 静态绑定

    在这个例子中,doSomething 方法在编译时就确定了具体实现,编译器会直接调用该方法的地址,这种方式性能较高。

    2. 动态绑定(Dynamic Dispatch)

    动态绑定在运行时确定方法的具体实现。Swift 中,动态绑定主要通过两种方式实现:

    • 虚方法表(V-Table):用于类的方法调用。
    • Objective-C 运行时:通过 @objc 和动态特性实现。
    2.1 虚方法表(V-Table)

    在类的继承层次中,Swift 会使用虚方法表来实现动态绑定,这与 C++ 的虚方法表类似。每个类都有一个虚方法表,记录了该类的方法实现地址。在方法调用时,通过虚方法表查找具体的实现地址。

    1. class ParentClass {
    2. func doSomething() {
    3. print("Doing something in ParentClass")
    4. }
    5. }
    6. class ChildClass: ParentClass {
    7. override func doSomething() {
    8. print("Doing something in ChildClass")
    9. }
    10. }
    11. let parent: ParentClass = ChildClass()
    12. parent.doSomething() // 动态绑定,通过虚方法表查找具体实现

    在这个例子中,doSomething 方法在运行时通过虚方法表查找具体实现,因为 parent 引用类型是 ParentClass,但实际对象是 ChildClass

    2.2 Objective-C 运行时

    通过使用 @objc 关键字,Swift 可以与 Objective-C 运行时交互,实现类似于 Objective-C 的消息传递机制。

    1. import Foundation
    2. class MyClass: NSObject {
    3. @objc func doSomething() {
    4. print("Doing something in Swift with dynamic dispatch")
    5. }
    6. }
    7. let myClass = MyClass()
    8. myClass.perform(#selector(MyClass.doSomething)) // 动态绑定,通过 Objective-C 运行时查找方法实现

    在这个例子中,doSomething 方法被标记为 @objc,因此可以通过 Objective-C 的运行时机制进行动态绑定。

    3. 方法调用的优化

    Swift 编译器在方法调用时会进行多种优化,以提高性能:

    • 内联(Inlining):对于短小且频繁调用的方法,编译器可能会内联方法的实现,避免函数调用的开销。
    • 去虚拟化(Devirtualization):在某些情况下,编译器可以确定具体的类型,从而将动态绑定转换为静态绑定。
    • 专用化(Specialization):对于泛型方法,编译器可以生成特定类型的实现,提高性能。

    4. 使用 dynamic 关键字

    Swift 提供了 dynamic 关键字,用于显式指定方法使用动态绑定。这通常用于需要动态特性的场景,如 KVO(键值观察)和 Objective-C 运行时特性。

    1. class MyClass: NSObject {
    2. @objc dynamic func doSomething() {
    3. print("Doing something dynamically")
    4. }
    5. }

    总结

    Swift 的方法调用机制主要分为静态绑定和动态绑定:

    • 静态绑定:在编译时确定方法实现,性能较高,适用于结构体、枚举和 final 方法。
    • 动态绑定:在运行时通过虚方法表或 Objective-C 运行时确定方法实现,适用于类的继承层次和需要动态特性的场景。

    理解这些机制,有助于编写高效且健壮的 Swift 代码,并在需要时合理使用动态特性。

  • 相关阅读:
    DBA 数据库管理 表管理 数据批量处理。表头约束
    (附源码)ssm考试题库管理系统 毕业设计 069043
    学员分享| 一个普通学员的HCIE-DATACOM备考之路!
    使用UiPath和AA构建的解决方案 2. HelpDesk生成Ticket
    高级套接字
    java_jsp-ssm留学申请服务系统springmvc
    Linux修改fs.inotify.max_user_watches(“外部文件更改同步可能很慢”和“当前的 inotify(7) 监视限制太低”)
    jquery常用方法积累
    【深度学习 AIGC】stablediffusion-infinity 在无界限画布中输出绘画 Outpainting
    Python入门都实践需要多长时间?|猿代码科技
  • 原文地址:https://blog.csdn.net/opentogether/article/details/139448535