能够在 objc 和 Swift 之间相互转换的类型称作bridged
类型,比如 Swift 中的String
可以作为NSString
传给 objc。
Foundation
Foundation 框架为程序提供了基础的功能。
Bridged 类型
详见表格
这些类型和它们对应的类型功能一样,在 Swift 中,可变性用var
和let
控制,所以不用两种类型。objc 的引用类型与它们所对应的 Swift 的值类型基本上相差NS
前缀。
在 Swift 与 objc 相互导入时,导入器会替换相关的 bridged 类型。
Renamed 类型
Swift 的 Foundation 重命名了一些类和协议,包括相关的枚举类型和常量。
一般,类都去掉了NS
前缀,也有一些特例:
- objc 特有的类或与 objc runtime 相关的类:
NSObject
,NSAutoreleasePool
,NSException
,NSProxy
- 平台特有的类:
NSBackgroundActivity
,NSUserNotification
,NSXPCConnection
- 有等价值类型的类,如 Bridged 类型所述:
NSString
,NSDictionary
,NSURL
- 没有等价类型的类,但在不久的将来会有的:
NSAttributedString
,NSRegularExpression
,NSPredicate
Foundation 框架中有很多枚举和常量,当 Swift 导入这些类型时,会把它们作为相关类的嵌套类型。如NSJSONReadingOptions
会导入为JSONSerialization.ReadingOptions
。
Strings
在 Swift 中要创建NSString
,可以用as
转型String
,也可以用字符串常量来创建。
|
|
Numbers
NSNumber
可以桥接 Swift 的数值类型,包括Int
, Double
, Bool
。
把数值类型转型为NSNumber
时,要用as?
操作符。
|
|
objc 平台相关的整形类型,如
NSUInteger
、NSInteger
,都与Int
对应。
Arrays
当桥接一个参数化的NSArray
对象时,其中的元素也会被桥接。如果没有参数化,就会桥接为类型[Any]
的数组。
|
|
|
|
可以直接用字面值定义一个NSArray
对象:
|
|
Sets
集合的桥接与数组类似,如果NSSet
没有明确参数化类型,就会桥接为Set<AnyHashable>
。
|
|
|
|
|
|
Dictionaries
为定义参数化类型的NSDictionary
桥接为[AnyHashable: Any]
。
|
|
|
|
|
|
Core Foundation
CF 类型会被导入为 Swift 类。还会提供内存管理注解,这样 Swift 就能自动管理 CF 对象的内存,包括你自己实例化的 CF 对象。In Swift, you can use each pair of toll-free bridged Foundation and Core Foundation types interchangeably. You can also bridge some toll-free bridged Core Foundation types to Swift standard library types if you cast to a bridging Foundation type first.
Remapped Types
Swift 导入 CF 类型时,编译器会重新映射这些类型的名字。从每个类型名最后移除Ref
,因为所有 Swift 类都是引用类型。
CFTypeRed
类型会重新映射为AnyObject
类型。
Memory Managed Objects
从注解过的API中返回的 CF 对象会被 Swift 自动管理内存,不需要自己调用CFRetain
, CFRelease
, CFAutorelease
。
如果你想要在你自己的 C 方法或 objc 方法中返回 CF 对象,可以用CF_RETURNS_RETAINED
、CF_RETURNS_NOT_RETAINED
宏来注解,就能自动插入内存管理语句。也可以用CF_IMPLICIT_BRIDGING_ENABLED
、CF_IMPLICIT_BRIDGING_DISABLED
宏,来包裹 C 方法声明,遵循 CF 所有权策略和命名策略,从而根据命名推断出内存管理。
Unmanaged Objects
当 Swift 导入的 API 没有注解,就不能自动管理返回的 CF 对象的内存。Swift 会将返回的 CF 对象包裹在Unmanaged<Instance>
结构中。所有间接返回的 CF 对象也是 unmanaged。如下是未注解的 C 方法:
|
|
Swift 这么导入:
|
|
当你从一个未注解的 API 收到一个非托管的对象时,要马上把它转化成一个内存管理对象。Unmanaged<Instance>
结构体提供两个方法来转化成内存管理对象——takeUnretainedValue()
和takeRetainedValue()
。这两个方法都返回原始的、解包的对象类型。
|
|
当然也可以用retain()
、release()
、autorelease()
方法来管理非托管对象,但这些方法不推荐。
Unified Logging
标准日志系统提供 API 来替代NSLog
方法。
Swift 中,可以用顶级的os_log(_:dso:log:type:_:)
方法与标准日志系统交互,在模块 os 的子模块 log 中。
|
|
用NSString
或printf
格式的字符串来格式化日志消息。
|
|
也可以明确日志的层级,如 Info、Debug、Error。
|
|
要对特定的子系统记录日志,可以创建OSLog
对象,明确子系统和分类,作为参数传给os_log
方法。
|
|
Cocoa Structures
把 Swift 代码转换回 objc 代码时,Cocoa 和 Foundation 中内置的结构体会转换为NSValue
实例。As a result, you can use an Objective-C structure from Swift in Cocoa APIs that accept only instances of reference types. This is true even though the instance’s defining type is bridged to Swift as a structure type.
下面的结构体会桥接为NSValue
:
- CATransform3D
- CLLocationCoordinate2D
- CGAffineTransform
- CGPoint
- CGRect
- CGSize
- CGVector
- CMTimeMapping
- CMTimeRange
- CMTime
- MKCoordinateSpan
- NSRange
- SCNMatrix4
- SCNVector3
- SCNVector4
- UIEdgeInsets
- UIOffset