4

混用Swift和objc - 使用Cocoa

 2 years ago
source link: https://rhetty.github.io/2017/04/10/%E6%B7%B7%E7%94%A8Swift%E5%92%8Cobjc-%E4%BD%BF%E7%94%A8Cocoa/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

能够在 objc 和 Swift 之间相互转换的类型称作bridged类型,比如 Swift 中的String可以作为NSString传给 objc。

Foundation

Foundation 框架为程序提供了基础的功能。

Bridged 类型

详见表格

这些类型和它们对应的类型功能一样,在 Swift 中,可变性用varlet控制,所以不用两种类型。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,也可以用字符串常量来创建。

import Foundation
let string: String = "abc"
let bridgedString: NSString = string as NSString
let stringLiteral: NSString = "123"
if let integerValue = Int(stringLiteral as String) {
print("\(stringLiteral) is the integer \(integerValue)")
// Prints "123 is the integer 123"

Numbers

NSNumber可以桥接 Swift 的数值类型,包括Int, Double, Bool

把数值类型转型为NSNumber时,要用as?操作符。

import Foundation
let number = 42
let bridgedNumber: NSNumber = number as NSNumber
let integerLiteral: NSNumber = 5
let floatLiteral: NSNumber = 3.14159
let booleanLiteral: NSNumber = true

objc 平台相关的整形类型,如NSUIntegerNSInteger,都与Int对应。

Arrays

当桥接一个参数化的NSArray对象时,其中的元素也会被桥接。如果没有参数化,就会桥接为类型[Any]的数组。

@property NSArray *objects;
@property NSArray<NSDate *> *dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;
var objects: [Any]
var dates: [Date]
func datesBeforeDate(date: Date) -> [Date] {}
func addDatesParsedFromTimestamps(timestamps: [String]) {}

可以直接用字面值定义一个NSArray对象:

let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"]
// schoolSupplies is an NSArray object containing three values

集合的桥接与数组类似,如果NSSet没有明确参数化类型,就会桥接为Set<AnyHashable>

@property NSSet *objects;
@property NSSet<NSString *> *words;
- (NSSet<NSString *> *)wordsMatchingPredicate:(NSPredicate *)predicate;
- (void)removeWords:(NSSet<NSString *> *)words;
var objects: Set<AnyHashable>
var words: Set<String>
func wordsMatchingPredicate(predicate: NSPredicate) -> Set<String> {}
func removeWords(words: Set<String>) {}
let amenities: NSSet = ["Sauna", "Steam Room", "Jacuzzi"]
// amenities is an NSSet object containing three values

Dictionaries

为定义参数化类型的NSDictionary桥接为[AnyHashable: Any]

@property NSDictionary *keyedObjects;
@property NSDictionary<NSURL *, NSData *> *cachedData;
- (NSDictionary<NSURL *, NSNumber *> *)fileSizesForURLsWithSuffix:(NSString *)suffix;
- (void)setCacheExpirations:(NSDictionary<NSURL *, NSDate *> *)expirations;
var keyedObjects: [AnyHashable: Any]
var cachedData: [URL: Data]
func fileSizesForURLsWithSuffix(suffix: String) -> [URL: NSNumber] {}
func setCacheExpirations(expirations: [URL: NSDate]) {}
let medalRankings: NSDictionary = ["Gold": "1st Place", "Silver": "2nd Place", "Bronze": "3rd Place"]
// medalRankings is an NSDictionary object containing three key-value pairs

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_RETAINEDCF_RETURNS_NOT_RETAINED宏来注解,就能自动插入内存管理语句。也可以用CF_IMPLICIT_BRIDGING_ENABLEDCF_IMPLICIT_BRIDGING_DISABLED宏,来包裹 C 方法声明,遵循 CF 所有权策略和命名策略,从而根据命名推断出内存管理。

Unmanaged Objects

当 Swift 导入的 API 没有注解,就不能自动管理返回的 CF 对象的内存。Swift 会将返回的 CF 对象包裹在Unmanaged<Instance>结构中。所有间接返回的 CF 对象也是 unmanaged。如下是未注解的 C 方法:

CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2)

Swift 这么导入:

func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged<CFString>! {
// ...

当你从一个未注解的 API 收到一个非托管的对象时,要马上把它转化成一个内存管理对象。Unmanaged<Instance>结构体提供两个方法来转化成内存管理对象——takeUnretainedValue()takeRetainedValue()。这两个方法都返回原始的、解包的对象类型。

let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
// memoryManagedResult is a memory managed CFString

当然也可以用retain()release()autorelease()方法来管理非托管对象,但这些方法不推荐。

Unified Logging

标准日志系统提供 API 来替代NSLog方法。

Swift 中,可以用顶级的os_log(_:dso:log:type:_:)方法与标准日志系统交互,在模块 os 的子模块 log 中。

import os.log
os_log("This is a log message.")

NSStringprintf格式的字符串来格式化日志消息。

let fileSize = 1234567890
os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize)

也可以明确日志的层级,如 Info、Debug、Error。

os_log("This is additional info that may be helpful for troubleshooting.", type: .info)

要对特定的子系统记录日志,可以创建OSLog对象,明确子系统和分类,作为参数传给os_log方法。

let customLog = OSLog("com.your_company.your_subsystem_name.plist", "your_category_name")
os_log("This is info that may be helpful during development or debugging.", log: customLog, type: .debug)

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK