原文地址:Working with Cocoa Frameworks
作为与OC交互的一部分,Swift提供了简单和高效的方式与Cocoa框架一起工作。
Swift自动将一些OC类型转换为Swift类型,以及自动将一些Swift类型转换为OC类型。能够在OC与Swift之间相互转换的类型被简称为桥接类型。例如,在Swift中,你可以传递一个String类型的数据给一个带有NSString类型参数的OC方法。另外,为了在Swift中看起来更自然,许多Cocoa框架,包括Foundation,AppKit和UIKit重新定义了他们的API。例如,NSCoder的decodeObjectOfClass(_:forKey:)利用Swift的泛型提供强类型签名。
Foundation
Foundation框架为应用程序和其他框架提供一些基础性的功能,包括数据存储、文本处理、日期和时间、排序和过滤、持久化以及网络相关功能。
桥接类型
Swift Foundation为如下的OC类型提供了对应的桥接类型:
这些Swift类型与其对应的类型有相同的功能。包含不可变和可变子类型的类族被桥接到同一个类型。Swift代码利用var和let去控制是否可修改,所以他不需要两种类。这些对应的类型能够像具有NS前缀的类一样被访问。
任何你可以使用桥接OC类型的地方,你都可以使用Swift类型来代替。这使得在Swift中你能够利用这些对应类型的功能。基于这个原因,在你的代码中你永远不需要使用桥接类型对应的类型。事实上,当Swift导入OC API时,导入器将OC中的这些类型进行了替换。同样的,当OC导入Switf API的时候,也做了替换。
类型关联其中最主要的一个好处是使得reason about your code很简单。获取更多关于值类型,参考Classes and Structures 和WWDC 2015 session 414 Building Better Apps with Value Types in Swift
如果需要使用桥接Foundation对象,可以使用as转换符来转换桥接类型。
Renamed Types
Swift Foundation重命名了类、协议以及一些相关的枚举和常量。
除以下几种特例,被导入的Foundation的类和协议去掉了NS前缀:
一些专门设计用来支持或者用于继承支持OC runtime的类,例如NSObject、NSAutoreleasePool、NSException、NSProxy
平台相关的类,例如NSBackgroundActivity、NSUserNotification、NSXPCConnection
有等价的Swift类,如桥接类型中描述的类
一些现在没有等价但是未来会有等价的类的一些类,例如NSAttributedString、NSRegularExpression、NSPredicate
Strings
Swift 桥接String和NSString。能够用as操作符将String转换为NSString,同样可以直接利用双引号创建一个NSString对象。
Numbers
Swift桥接NSNumber到Swift的算术类型,包括Int、Double、Bool。
可以使用as将Swift的算术类型转换为NSNumber。因为NSNumber能够包含多种类型,所以应该使用as?将NSNumber转换到Swift的类型,否则可能引发崩溃。同样也可以直接用浮点数、整数、bool值创建NSNumber类型。
Arrays
Array---NSArray。当桥接模板化的NSArray到Array时,转换会非常顺利。但是如果没有指定类型,那么Array中的类型将是[Any].
Sets
如果没有模板化,将是Set<AnyHashable>
Dictionaries
如果NSDictionary中没有模板化,将是[AnyHashable: Any]
Core Foundation
Core Foundation类型被导入为Swift类。当出现内存管理注释时,Swift自动管理Core Foundation中的对象内存,包括由我们自己实例化的Core Foundation对象。在Swift中,可以自由变换toll-free bridges Foundation和Core Foundation类型。同样如果你转换了bridging Foundation type,你也可以桥接一些toll-free bridged Core Foundation类型到Swift。
Remapped Types
当Swift导入Core Foundation类型时,编译器重新映射了这些类型。由于Swift本身是引用类型,编译器移除了每种类型结尾的Ref。
CFTypeRef统一映射为AnyObject类型。所以,当你需要使用CFTypeRef时,使用AnyObject。
Memory Managed Objects
在 Swift 中,从 annotated APIs 返回的 Core Foundation 对象能够自动进行内存管理--你不再需要调用自身的CFRetain,CFRelease,或者CFAutorelease函数。
如果你从自身的C函数和 Objective-C 方法中返回一个 Core Foundation 对象,为了自动引入内存管理,你需要用CF_RETURNS_RETAINED或者CF_RETURNS_NOT_RETAINED注释这个对象。同样你需要使用CF_IMPLICIT_BRIDGING_ENABLED和CF_IMPLICIT_BRIDGING_DISABLED包裹C函数声明,这使得Core Foundation?????
Unmanned Objects 未托管对象
当Swift导入未注释的APIs时,编译器无法对返回的Core Foundation对象进行内存管理。Swift使用Unmanned<Instance>包裹这些对象。那些间接返回的对象也是难以管理的。例如:
CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2)
对应的Swift:
func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged! {
// ...
}
当你从 unannotated APIs 接收了一个难以管理的对象,在使用它之前,你必须要将它转换为一个能够内存管理的对象。在这方面,Swift 可以帮你进行内存管理而不用自己动手。同时,Unmanaged结构也提供了两个方法来把一个难以管理的对象转换为一个可内存管理的对象--takeUnretainedValue()方法和takeRetainedValue()方法。这两个方法会返回原始的,开放的对象类型。您可以根据您实际调用的APIs返回的unretained或retained的对象,来选择哪一方法更合适。
比如,假设这里有一个 C 函数,这个函数在返回值前不会释放CFString对象。在使用这个对象前,您使用takeUnretainedValue()函数,以将它转换为一个能够内存管理的对象。
let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
你也可以在一个非托管的对象中使用retain(),release()和autorelease()方法,但是这种做法并不值得推荐。
Unified Logging
统一的日志系统提供了一个API来捕获所有等级的系统信息,同时他也是NSLog的替代品。
os.log
可以指定log的等级:Info、Debug、Error