Swift与OC混编
Swift调OC
在Swift项目中调用OC类中的方法需要有个{targetName}-Bridging-Header.h文件,在这个文件中导入OC要暴露给Swift的类。
{targetName}-Bridging-Header.h文件的创建有2种方式
1.自己手动创建,然后在配置文件的Object-C Bridging Header中添加这个{targetName}-Bridging-Header.h文件的路径
2.在Swift项目工程中创建一个OC类,此时Xcode会自动帮助创建。


3.在Swift中使用OC类
1 2 3 4 5 6 7 8 9 10 11 12 13 | import UIKit class ViewController : UIViewController { override func viewDidLoad () { super . viewDidLoad () // Do any additional setup after loading the view. let p = Person (); p . name = "jack" ; p . age = 11 ; p . say (); } } |
1 | @ _silgen_name ( "sum" ) func swift_sum ( a : Int , b : Int ) - > Int |
OC调Swift
Swift项目在创建时就默认生成了一个{targetName}-Swift.h文件,用于暴露Swift类给OC使用。注意这里的targetName不允许使用-链接单词,如果出现这种情况会把-自动改成_进行单词连接。
如下,当前项目名是Swift-OC,而targetName被自动改成了Swift_OC。

Swift暴露给OC类使用时需要做一定的修改。
1.要暴露的类需要继承自NSObject
2.要暴露成员变量和方法给OC时,需要加@objc声明。
3.要暴露全部信息时,包含成员变量和方法以及扩展中的信息,则要在类前面加@objcMembers进行声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @ objcMembers class Car : NSObject { var speed : Float ; var name : String ; init ( speed : Float , name : String ) { self . speed = speed ; self . name = name ; } func run () - > Void { print ( "出发,时速:\( self . speed )" ) } } extension Car { func circleRun () { print ( "跑圈,时速:\( self . speed )" ) } } |
Swift中@objc的使用
可以使用@objc重命名swift暴露给oc的方法
selector是oc的runtime里使用的一套东西,只有swift中的类暴露给OC是才能正常使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @ objcMembers class Car : NSObject { var speed : Float ; @objc ( bigName ) //重写暴露给OC的方法 var name : String ; init ( speed : Float , name : String ) { self . speed = speed ; self . name = name ; } func run () - > Void { print ( "出发,时速:\( self . speed )" ) } func runPerform () - > Void { perform (# selector ( run )) } } extension Car { @objc ( bigRun ) func circleRun () { print ( "跑圈,时速:\( self . speed )" ) } } |
Swift中被@objc 修改的协议可以被OC实现
1 | @objc protocol RunProtocol {} |
Swift的类中中被@objc dynamic 修改的方法 走runtime的那套消息发送机制
1 2 3 4 5 | class Computer : NSObject { @objc dynamic func work ( num : Int ) { print ( "工作时长:\( num )" ) } } |
Swift的类中中被@objc dynamic 修改的属性可以进行KVC/KVO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Person : NSObject { @objc dynamic var age : Int = 10 override init () { super . init () self . addObserver ( self , forKeyPath : "age" , options : . new , context : nil ) } override class func observeValue ( forKeyPath keyPath : String ?, of object : Any ?, change : [ NSKeyValueChangeKey : Any ]?, context : UnsafeMutableRawPointer ?) { print ( "observer回调:\( change ! )" ) } deinit { self . removeObserver ( self , forKeyPath : "age" ) } } |
Swift与OC互相调用理解
1.Swift要暴露给OC调用,为什么要继承自NSObject?
OC的方法调用走的runtime的objc_sendMsg(), 这就需要isa指针, 而NSObject中有isa指针,所以要继承自NSObject
2.Swift调用OC桥接类的方法是怎么调用的,OC调用Swift暴露的方法又是如何调用的?
Swift调用自己定义的纯Swift方法底部走的是C++虚函数表那套。
Swift调用OC桥接类的方法底层走的还是OC的objc_msgSender机制,因为OC文件被编译后是转换的消息发送代码。
OC调用Swift暴露的方法时,因为是继承自NSObject, 所以底部走的还是objc_sendMsg机制
3.对于Swift类继承了NSObject,再在swift调用时,是怎么调用的?
底层走的还是Swift的需函数表那套,这套性能更高。
如何让Swift的方法走Runtime的消息转发机制呢?
通过在方法前面添加dynamic修饰
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @ objcMembers class Car : NSObject { var speed : Float ; @objc ( bigName ) //重写暴露给OC的方法 var name : String ; init ( speed : Float , name : String ) { self . speed = speed ; self . name = name ; } dynamic func fillOil () - > Void { print ( "加油" ) } } |
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了