[2014-08-10 01:05] │ entry #1435

2.1. 与 Objective-C API 交互

2014 年 8 月 10 日 │ 编程开发 │ 0 评论 │ 阅读 4

扩展(Extensions)

Swift 的扩展和 Objective-C 的类别(Category)相似。扩展为原有的类,结构和 枚举丰富了功能,包括在 Objective-C 中定义过的。你可以为系统的框架或者你 自己的类型增加扩展,只需要导入合适的模块并且保证你在 Objective-C 中使用 的类、结构或枚举拥有相同的名字。

举个例子,你可以扩展 UIBezierPath 类来为它增加一个等边三角形,这个方法只需 提供三角形的边长与起点。

page13image5368 page13image6696

//Swift
extension UIBezierPath {
    convenience init(triangleSideLength: Float, origin: CGPoint) {
       self.init()
       let squareRoot = Float(sqrt(3))
       let altitude = (squareRoot * triangleSideLength) / 2
       moveToPoint(origin)
       addLineToPoint(CGPoint(triangleSideLength, origin.x))
       addLineToPoint(CGPoint(triangleSideLength / 2, altitude))
       closePath()

} }

你也可以使用扩展来增加属性(包括类的属性与静态属性)。然而,这些属性必须
是通过计算才能获取的,扩展不会为类,结构体,枚举存储属性。下面这个例子为

类增加了一个叫 的属性。

 

CGRect

area

//Swift
extension CGRect {
    var area: CGFloat {
    return width * height
    }
}
let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area
// area: CGFloat = 500.0

 

你同样可以使用扩展来为类添加协议而无需增加它的子类。如果这个协议是在 Swift 中被定义的,你可以添加 comformance 到它的结构或枚举中无论它们在 Objective-C 或在 Swift 中被定义。
你不能使用扩展来覆盖 Objective-C 类型中存在的方法与属性。 闭包(Closures)
Objective-C 中的blocks会被自动导入为 Swift 中的闭包。例如,下面是一个 Objective-C 中的 block 变量:

而它在 Swift 中的形式为

Swift 的闭包与 Objective-C 中的 blocks 能够和睦相处,所以你可以把一个 Swift 闭包传递给一个把 block 作为参数的 Objective-C 函数。Swift 闭包与函数 具有互通的类型,所以你甚至可以传递 Swift 函数的名字。

闭包与 blocks 语义上想通但是在一个地方不同:变量是可以直接改变的,而不是 像 block 那样会拷贝变量。换句话说,Swift 中变量的默认行为与 Objective-C 中 __block 变量一致。

 

//Objective-C
void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* … */}

page14image18272 page14image18696 page14image18856 page14image19280  page14image19600

//Swift
let completionBlock: (NSData, NSError) -> Void = {data, error in /* … */}
page15image1608
比较对象(Object Comparison)
当比较两个 Swift 中的对象时,可以使用两种方式。第一种,使用(==),判断 两个对象内容是否相同。第二种,使用(===),判断常量或者变量是否为同一个对 象的实例。
Swift 与 Objective-C 一般使用 == 与 === 操作符来做比较。Swift 的 == 操作 符为源自 NSObject 的对象提供了默认的实现。在实现 == 操作符时,Swift 调 用 NSObject 定义的 isEqual: 方法。

NSObject 类仅仅做了身份的比较,所以你需要在你自己的类中重新实现 isEqual: 方法。因为你可以直接传递 Swift 对象给 Objective-C 的 API,你也应该为这些 对象实现自定义的 isEqual: 方法,如果你希望比较两个对象的内容是否相同而不 是仅仅比较他们是不是由相同的对象派生。

作为实现比较函数的一部分,确保根据 Object comparison 实现对象的 hash 属 性。更进一步的说,如果你希望你的类能够作为字典中的键,也需要遵从 Hashable 协议以及实现 hashValues 属性。

Swift 类型兼容性(Swift Type Compatibility)

当你定义了一个继承自NSObject或者其他 Objective-C 类的 Swift 类,这些类都 能与 Objective-C 无缝连接。所有的步骤都有 Swift 编译器自动完成,如果你从 未在 Objective-C 代码中导入 Swift 类,你也不需要担心类型适配问题。另外一 种情况,如果你的 Swift 类并不来源自 Objectve-C 类而且你希望能在 Objecive- C 的代码中使用它,你可以使用下面描述的 @objc 属性。

@objc 可以让你的 Swift API 在 Objective-C 中使用。换句话说,你可以通过在任 何 Swift 方法、类、属性前添加@objc,来使得他们可以在 Objective-C 代码中使 用。如果你的类继承自 Objective-C,编译器会自动帮助你完成这一步。编译器还会 在所有的变量、方法、属性前加 @objc,如果这个类自己前面加上了@objc关键 字。当你使用@IBOutlet,@IBAction,或者是@NSManaged 属性时,@objc 也会自动加在 前面。这个关键字也可以用在 Objetive-C 中的 target-action 设计模式中,例 如,NSTimer 或者 UIButton。

当你在 Objective-C 中使用 Swift API,编译器基本对语句做直接的翻译。例如, Swift API func playSong(name: String)会被解释为

*)name。然而,有一个例外:当在 Objective-C 中使用 Swift 的初始化函数,编译 器会在方法前添加“initWith”并且将原初始化函数的第一个参数首字母大写。例如, 这个 Swift 初始化函数 init (songName: String, artist: String 将被翻译为 (instancetype)initWithSongName:(NSString *)songName artist:(NSString *)artist 。 Swift 同时也提供了一个@objc关键字的变体,通过它你可以自定义在 Objectiv-C 中转换的函数名。例如,如果你的 Swift 类的名字包含 Objecytive-C 中不支持的 字符,你就可以为 Objective-C 提供一个可供替代的名字。如果你给 Swift 函数 提供一个 Objecytive-C 名字,要记得为带参数的函数添加(:)
page16image5400

- (void)playSong:(NSString

page16image6472

page16image7032 page16image7192 page16image7776

page16image8784 page16image10272
page16image17544 page16image17968 page16image18560 page16image19728 page16image21056

//Swift
@objc(Squirrel)
class Белка {
    @objc(initWithName:)
    init (имя: String) { /*...*/ }
    @objc(hideNuts:inTree:)
    func прячьОрехи(Int, вДереве: Дерево) { /*...*/ }

}

当你在 Swift 类中使用@objc(<#name#>)关键字,这个类可以不需要命名空间即可在 Objective-C 中使用。这个关键字在你迁徙 Objecive-C 代码到 Swift 时同样也非 常有用。由于归档过的对象存贮了类的名字,你应该使用@objc(<#name#>)来声明与 旧的归档过的类相同的名字,这样旧的类才能被新的 Swift 类解档。

Objective-C 选择器(Selectors)

一个 Objective-C 选择器类型指向一个 Objective-C 的方法名。在 Swift 时代, Objective-C 的选择器被Selector结构体替代。你可以通过字符串创建一个选择 器,比如 let mySelector: Selector = “tappedButton:”。因为字符串能够自动转换为 选择器,所以你可以把字符串直接传递给接受选择器的方法。page16image35192 page16image36520 page16image37104 page16image37696 page16image38440 page16image39032

//Swift
import UIKit
class MyViewController: UIViewController {
    let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
    init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
super.init(nibName: nibName, bundle: nibBundle)
    myButton.targetForAction("tappedButton:", withSender: self)
}
func tappedButton(sender: UIButton!) {
    println("tapped button")

}

}

注意: performSelector:方法和相关的调用选择器的方法没有导入到 Swift 中因为 它们是不安全的。
如果你的 Swift 类继承自 Objective-C 的类,你的所有方法都可以用作 Objective-C 的选择器。另外,如果你的 Swift 类不是继承自 Objective-C,如果 你想要当选择器来使用你就需要在前面添加@objc 关键字,详情请看 Swift 类型兼 容性。 

 

#2014#API#iOS#Mac#Objective-C#Swift#交互#存档#教程#方法#编程

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理。