Swift and ObjectiveC Interop (Swift 与 Objective-C 之间的交互)
2015-10-22 17:41
381 查看
主要介绍原有 Objective-C 中的一些类型在 Swift 中的操作问题。差不多就能知道,你在 Swift 如何对 Objective-C (Foundation) 原生类型进行操作以及和 Swift 类型互转。
瞎写的,有错或者不明白的地方直接告诉我。转载注明我或者 SwiftChina 。
参考资料是 我的 Github : andelf/Defines-Swift 是我dump出的定义。10w行swift代码。
数值类型统一用
没有泛型支持,字典或者数组更多用
数值类型众多 (
有几个属性用于和 Objective-C 之间的交互。
用于函数类型前,标记后面的 block 是 Objective-C 的。个人觉得编译器会自动转换相关的 block 类型。
然后需要预备下几个属性的知识。
Swift 中的隐式类型转换。有另一篇文章介绍。
就是 final 了。
经过反汇编查看,相当于
表示可以从 Swift 字面常量转换而得。比如
大概有 IntegerLiteralConvertible, FloatLiteralConvertible, StringLiteralConvertible, ArrayLiteralConvertible, DictionaryLiteralConvertible, CharacterLiteralConvertible 等。
顾名思义。就是相当于这个 Swift 类型可以和某一 Objective-C 类型对等,可以相互转换。
Conditional 多了个判断函数,也就是说这个类型可能是并没有对等起来的,什么情况下用呢,目前猜测应该是带泛型参数的类型中用到,有的泛型可以对应,有的不可以。
这个具体暂时不清楚。反射相关的两个 protocol 。
这两个用于 Swift 的 for-in 循环,简单说就是,实现了
然后
英汉字典拿来。所以其实为了让 Objective-C 类型在 Swift 代码中正常工作,这个是必不可少的。
通过
Swift 定义。其中 name 为 Objective-C 下的名字。
例如
所有可能为
其中类型参数
也就是说,可以直接
Swift 字面常量获得。
实际上 Objective-C 中的
1, 0 。
所以 Swift
这就是为什么官方文档说 Swift 中
Objective-C 基本是相同操作的。其实都是背后的隐式类型转换。
同时 Foundation 还为
可以从字面常量直接获得。还实现了到
对应于
for-in 操作。其中
Foundation 没有的。 当然
新类型
for-in .
一般说来,你在 Swift 项目新建 Objective-C 类的时候,直接弹出是否创建 Bridge Header 的窗口,点 YES 就是了,这时候一般多出来个
如果没有自动的话,这个配置在项目的 Build Settings 中的 Swift Compiler – Code Generation 子项里。
说到底,其实是调用编译命令的
Header 文件。
然后你就可以把你的 Objective-C Class 的 .h 文件都 import 到这个 Herder 文件里了。
所有 Swift 代码都可以直接调用。完全透明,自动生成。
头文件是
import 。
不要吝啬你的键盘大量地加入
具体实现据我猜测是这样,先 swift 调用
Objective-C 的 Header,同时 swift 编译为模块,然后再编译一次。
头文件内容大概是会包含一堆宏定义。然后是 Swift 的类定义等。这里可以看到 Swift 的 mangling 名字。
这里只先考虑一个 Swift 项目使用 Objective-C 代码的情况,这个应该暂时比较多见(使用旧的 MVC 代码,用新的 Swift 创建 ui 一类)。
编译所有
(其中包含
由于选项里有
Objective-C 文件可以直接 import 对应的
编译
链接所有
瞎写的,有错或者不明白的地方直接告诉我。转载注明我或者 SwiftChina 。
参考资料是 我的 Github : andelf/Defines-Swift 是我dump出的定义。10w行swift代码。
预备知识
Objective-C (Cocoa) 特色
数值类型统一用 NSNumber,不区分具体。大量操作在指针上进行,也就隐含着一切可能出错的调用都会返回
nil。
没有泛型支持,字典或者数组更多用
id类型。
对应 Swift 特色
数值类型众多 (Int, UInt, Float, Double, ...),无指针(
UnsafePointer这类用于和其他代码交互的结构不计,
&+
inout认为是引用。)。
nil用于
Type?,
Type!。字典和数组用泛型表示。
一些属性
有几个属性用于和 Objective-C 之间的交互。
@objc
和 @objc(a_name_defined_in_objc)
@objc_block
用于函数类型前,标记后面的 block 是 Objective-C 的。个人觉得编译器会自动转换相关的 block 类型。然后需要预备下几个属性的知识。
@conversion
Swift 中的隐式类型转换。有另一篇文章介绍。
@final
就是 final 了。
@transparent
经过反汇编查看,相当于 inline的作用。同时生成的
.swiftmodule文件依然带有原函数实现。这个很高大上。保证了
inline特性在包外可用。
重要 Swift protocol
*LiteralConvertible
表示可以从 Swift 字面常量转换而得。比如 let a: Type = 100, 那么 Type 必须实现 IntegerLiteralConvertible。
大概有 IntegerLiteralConvertible, FloatLiteralConvertible, StringLiteralConvertible, ArrayLiteralConvertible, DictionaryLiteralConvertible, CharacterLiteralConvertible 等。
_BridgedToObjectiveC
_ConditionallyBridgedToObjectiveC
顾名思义。就是相当于这个 Swift 类型可以和某一 Objective-C 类型对等,可以相互转换。Conditional 多了个判断函数,也就是说这个类型可能是并没有对等起来的,什么情况下用呢,目前猜测应该是带泛型参数的类型中用到,有的泛型可以对应,有的不可以。
1 2 3 4 5 6 | protocol _BridgedToObjectiveC { typealias ObjectiveCType class func getObjectiveCType() -> Any.Type func bridgeToObjectiveC() -> ObjectiveCType class func bridgeFromObjectiveC(source: ObjectiveCType) -> Self? } |
Reflectable
Mirror
这个具体暂时不清楚。反射相关的两个 protocol 。
Sequence
Generator
这两个用于 Swift 的 for-in 循环,简单说就是,实现了 Sequence协议的对象可以
.generate()出一个
Generator,
然后
Generator可以不断地
.next()返回
Type?,其中
Type是这个序列的泛型。
Hashable
Equatable
英汉字典拿来。所以其实为了让 Objective-C 类型在 Swift 代码中正常工作,这个是必不可少的。
第一部分,类型交互
For 类、方法、协议
通过 @objc(name)转为
Swift 定义。其中 name 为 Objective-C 下的名字。
例如
1 2 3 4 5 67 | @objc(NSNumber) class NSNumber : NSValue { @objc(init) convenience init() @objc var integerValue: Int { @objc(integerValue) get {} } ... } @objc(NSCopying) protocol NSCopying { @objc(copyWithZone:) func copyWithZone(zone: NSZone) -> AnyObject! } |
nil的指针类型几乎都被转为
Type!,由于
ImplicitlyUnwrappedOptional的特性,所以几乎用起来一样。
For 基础数字类型
Int,
UInt,
Float,
Double均实现了
_BridgedToObjectiveC,
其中类型参数
ObjectiveCType均为
NSNumber。
也就是说,可以直接
.getObjectiveCType()获取到
NSNumber,然后剩下的就很熟悉了。
NSNumber实现了
FloatLiteralConvertible,
IntegerLiteralConvertible,所以其实,也可以直接从
Swift 字面常量获得。
For Bool
实际上 Objective-C 中的 BOOL是某一数字类型,
YES,
NO也分别是
1, 0 。
所以 Swift
Bool实现了
_BridgedToObjectiveC,对应于
NSNumber类型。
For String
NSString实现了
StringLiteralConvertible,可以直接通过字面常量获得,同时还有到
String的隐式类型转换。
String实现了
_BridgedToObjectiveC对应于
NSString。
1 2 3 | extension NSString { @conversion func __conversion() -> String } |
String和
Objective-C 基本是相同操作的。其实都是背后的隐式类型转换。
同时 Foundation 还为
String扩充了很多方法,发现几个比较有意思的是
._ns,直接返回
NSString,
._index(Int)返回
String.Index,等等。
For Array
NSArray实现了
ArrayLiteralConvertible,
可以从字面常量直接获得。还实现了到
AnyObject[]的隐式类型转换。
Array<T>实现了
_ConditionallyBridgedToObjectiveC,
对应于
NSArray.
NSArray还实现了
Sequence协议,也就是可以通过
for-in 操作。其中
generate()返回
NSFastGenerator类,这个应该是在原有
Foundation 没有的。 当然
.next()返回
AnyObject?
For Dictionary
NSDictionary实现了
DictionaryLiteralConvertible,
Sequence。同时还实现了到
Dictionary<NSObject, AnyObject>的隐式类型转换。
Dictionary<KeyType, ValueType>实现了到
NSDictionary的隐式类型转换。实现了
_ConditionallyBridgedToObjectiveC对应于
NSDictionary。
其他扩充类型
新类型 NSRange,实现了
_BridgedToObjectiveC,对应于
NSValue,实现了到
Range<Int>的隐式类型转换。
NSMutableSet
NSMutableDictionary
NSSet
NSMutableArray均实现了
Sequence可以
for-in .
第二部分:从 Swift 调用 Objective-C
一般说来,你在 Swift 项目新建 Objective-C 类的时候,直接弹出是否创建 Bridge Header 的窗口,点 YES 就是了,这时候一般多出来个 ProjectName-Bridging-Header.h。
如果没有自动的话,这个配置在项目的 Build Settings 中的 Swift Compiler – Code Generation 子项里。
说到底,其实是调用编译命令的
-import-objc-header参数,后面加上这个
Header 文件。
然后你就可以把你的 Objective-C Class 的 .h 文件都 import 到这个 Herder 文件里了。
所有 Swift 代码都可以直接调用。完全透明,自动生成。
第三部分:从 Objective-C 调用 Swift
头文件是 ProjectName-Swift.h。直接
import 。
不要吝啬你的键盘大量地加入
@objc属性就是了。
具体实现据我猜测是这样,先 swift 调用
-emit-objc-header
-emit-objc-header-path参数控制生成
Objective-C 的 Header,同时 swift 编译为模块,然后再编译一次。
头文件内容大概是会包含一堆宏定义。然后是 Swift 的类定义等。这里可以看到 Swift 的 mangling 名字。
1 2 3 4 5 67 | SWIFT_CLASS("_TtC5Hello11AppDelegate") @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic) UIWindow * window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; - (void)applicationWillResignActive:(UIApplication *)application; - (void)applicationDidEnterBackground:(UIApplication *)application; - (void)applicationWillEnterForeground:(UIApplication *)application; - (void)applicationDidBecomeActive:(UIApplication *)application; - (void)applicationWillTerminate:(UIApplication *)application; - (instancetype)init OBJC_DESIGNATED_INITIALIZER; @end |
第四部分:一个 Swift 和 Objective-C 混合项目的编译过程
这里只先考虑一个 Swift 项目使用 Objective-C 代码的情况,这个应该暂时比较多见(使用旧的 MVC 代码,用新的 Swift 创建 ui 一类)。编译所有
X.swift文件到
X.o(with
-emit-objc-header,
-import-objc-header)
(其中包含
.swiftmodule子过程)
由于选项里有
-emit-objc-header,所以之后的
Objective-C 文件可以直接 import 对应的
ProjectName-Swift.h
编译
X.m到
X.o
链接所有
.o生成可执行文件
相关文章推荐
- Fatal error: Using $this when not in object context in 解决方法
- Objective-C学习-UILabel的使用
- Objective-C 程序设计 第六章
- 【Objective-C学习记录】01-基础概念
- Objective-C编码规范(待补充)
- Objective-C Runtime 运行时之二:成员变量与属性
- Objective-C Runtime 运行时之一:类与对象
- Objective-C Runtime 运行时之三:方法与消息
- objective-C nil,Nil,NULL 和NSNull的小结
- Implicit Object in JSP
- 【IOS开发】objective-c的笔记
- C++STL学习(9)仿函数(function objects, functor)
- Ubuntu下设置外部库(so,shared object)运行环境和ROS中使用外部库编译
- volley JsonObjectRequest 提交参数
- object转json 少参数
- 读effective objective-c 2.0 整理文章 - 11条 理解objc_msgSend的作用
- Get SQL String From Query Object In Entity Framework
- 特性二、Objective-C的Attributed属性
- 2015 Objective-C 新特性
- Objective-C高级编程——KVO(一)