面试题答案
一键面试- 确保调用到正确的Swift子类实现:
- 在Objective - C中,虚方法(Objective - C中没有严格意义的虚方法概念,这里类比C++虚函数的概念,实际是动态方法调度)是通过动态方法调度机制来实现的。当在Swift子类
SubSwiftClass
中重写BaseObjCClass
的performAction
方法时,只要遵循Objective - C的动态方法调度规则,就可以确保通过BaseObjCClass
类型的指针调用performAction
方法时,会调用到SubSwiftClass
中重写的实现。 - 为了在Swift中与Objective - C进行交互,需要在Swift类定义前添加
@objc
修饰符,这样Swift类才能在Objective - C运行时可见,并且其重写的方法也能被正确调度。
- 在Objective - C中,虚方法(Objective - C中没有严格意义的虚方法概念,这里类比C++虚函数的概念,实际是动态方法调度)是通过动态方法调度机制来实现的。当在Swift子类
- 不同编译选项和运行环境下的机制变化:
- 编译选项:
- 通常情况下,只要Swift类标记了
@objc
,并且方法签名在Objective - C和Swift之间能够正确映射,动态方法调度就会正常工作。如果在编译时开启了优化选项,编译器可能会对方法调用进行内联等优化,但这一般不会影响动态方法调度的正确性。例如,在Xcode中,可以通过设置Optimization Level
编译选项来调整优化程度。
- 通常情况下,只要Swift类标记了
- 运行环境:
- 在不同的iOS或macOS版本中,Objective - C运行时的底层实现基本保持一致,所以动态方法调度机制不会有太大变化。但是,在一些特殊情况下,如应用程序在不同架构(如ARM64、x86_64)的设备上运行时,由于指令集等差异,方法调用的底层实现细节可能略有不同,但整体的动态方法调度逻辑是不变的。
- 编译选项:
- 代码示例:
- Objective - C基类代码(BaseObjCClass.h):
#import <Foundation/Foundation.h>
@interface BaseObjCClass : NSObject
- (void)performAction;
@end
- Objective - C基类代码(BaseObjCClass.m):
#import "BaseObjCClass.h"
@implementation BaseObjCClass
- (void)performAction {
NSLog(@"BaseObjCClass performAction");
}
@end
- Swift子类代码(SubSwiftClass.swift):
import Foundation
@objc class SubSwiftClass: BaseObjCClass {
override func performAction() {
print("SubSwiftClass performAction")
}
}
- 测试代码(在Objective - C中测试,假设在main.m文件中):
#import <Foundation/Foundation.h>
#import "BaseObjCClass.h"
// 引入Swift生成的头文件,假设项目名为MyProject
#import "MyProject - Swift.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
BaseObjCClass *baseObj = [[SubSwiftClass alloc] init];
[baseObj performAction];
}
return 0;
}
在上述代码中,SubSwiftClass
标记了@objc
,重写了performAction
方法。通过BaseObjCClass
类型的指针baseObj
指向SubSwiftClass
的实例,并调用performAction
方法,会调用到SubSwiftClass
中重写的实现。