使用Swift与Cocoa和Objective-C交互-(7)用 Objective-C 的行为来写 Swift 类

swift 发布于 2017年09月23日
继承自 Objective-C 类

在 Swift 中,你可以定义 Objective-C 类的子类。要在 Swift 中创建 Objective-C 的子类,在 Swift 类名后面添加一个冒号(:),后面紧随着 Objective-C 类的名称。

import UIKit

class MySwiftViewController: UIViewController {
    // define the class
}

你得到了所有 Objective-C 父类中提供的功能。如果你要提供你对父类方法自己的实现,记得使用 override 关键字。

采用协议

在 Swift 中,你可以采用定义在 Objective-C 中的协议。就像 Swift 协议,Objective-C 协议也在父类名后面用逗号分隔开。

class MySwiftViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    // define the class
}

如果你要在 Swift 代码中引用 UITableViewDelegate 协议,直接用 UITableViewDelegate 来引用它(就像在 Objective-C 中用 id<UITableViewDelegate> 来引用一样)。

因为 Swift 中没有类的命名空间和协议的定义, Objective-C 中的 NSObject 协议在 Swift 中被重新映射为 NSObjectProtocol

创建初始化方法和清理方法

Swift 编译器为了提升你代码的安全性和可预测性,要确保你的初始化方法中对所有的属性都进行了初始化。另外,不像 Objective-C,在 Swift 中没有单独的内存分配供调用方法使用。你要使用原生的 Swift 初始化语法,即便当你使用 Objective-C 类的时候——Swift 将 Objective-C 的初始化方法转化成 Swift 初始化方法。你可以在初始化方法这一章中读到更多实现你自己初始化方法的内容。

当你想在你的类清理的时候执行一些附加的清理工作的时候,你可以实现一个清理方法来代替 dealloc 方法。Swift 清理方法会被自动调用,整好在实例销毁之前。 Swift 在调用你子类的清理方法时,也会自动调用父类的清理方法。当你使用 Objective-C 类的时候或者你的 Swift 类继承自 Objective-C 类的时候, Swift 也会为你调用你的父类的 dealloc 方法。你可以在清理方法一章中查看更多关于如何自己实现清理方法的内容。

与 Interface Builder 集成

Swift 编译器包含了为你的 Swift 类打开 interface builder 特性的属性。就像在 Objective-C 中, 你可以在 Swift 中使用 outlet,action, live rendering。

使用 Outlet 和 Action

Outlet 和 action 能让你将你的代码与 Interface Builder 中的用户界面进行关联。要在 Swift 中使用 outlet 和 action,需要在属性和方法定义的前面加上 IBOutletIBAction。同样使用 IBOutlet 来定义 outlet 集合——只需要将类型指定为 array。

当你在 Swift 中定义一个 outlet,编译器自动会将这个类型转换成隐式拆包后的 Optional 值,而且是弱引用的,并为它赋初始值为 nil。实际上,编译器将 IBOutlet var name: Type 替换为 IBOutlet weak var name: Type! = nil。编译器已经将它转换为隐式拆包的 Optional 类型,这样就不必一定要在初始化方法中为它指定初始值。因为在从 storyboard 或 xib 文件初始化后,你可以假设 outlet 已经被连接上。Outlet 默认是 weak 引用,你创建的 outlet 默认都是弱引用关系。

例如,如下的 Swift 代码中的类,定义了一个 outlet,一个 outlet 集合,还有一个 action:

class MyViewController: UIViewController {
    @IBOutlet var button: UIButton
    @IBOutlet var textFields: [UITextField]
    @IBAction func buttonTapped(AnyObject) {
        println("button tapped!")
    }
}

因为 buttonTapped: 方法传入的参数没有被使用,参数名就可以忽略掉。

Live Rendering

你可以使用两个不同的属性——@IBDesignable 和 @IBInspectable——来打开在 Interface Builder 设计的实时交互性的自定义视图。当你创建一个继承自 UIViewNSView 的自定义视图,你可以在类定义前面加上 @IBDesignable 属性。当你将自定义视图添加到 Interface Builder 后(在 inspector 面板中设置视图的自定义类),Interface Builder 在 canvas 上渲染你的视图。

Live rendering 只能从导入的框架中使用。

你还可以为类的属性添加 @IBInspectable 属性。在你将自定义视图添加到 Interface Builder 后,你可以在 inspector 中编辑这些属性。

@IBDesignable
class MyCustomView: UIView {
    @IBInspectable var textColor: UIColor
    @IBInspectable var iconHeight: CGFloat
    /* ... */
}
指定类属性的属性

在 Objective-C 中,类的属性有一系列的特性可以对属性的行为指定一些附加信息。在 Swift 中,你用不同的方式来指定这些特性。

Strong 和 Weak

Swift 的属性默认情况下是 strong 的。使用 weak 关键字来表示属性是一个指向存储为它的值的对象的弱引用。这个关键字只适用于那些 Optional 类型的属性。关于更多信息,可以查看 Attributes 一章。

可读可写和只读

在 Swift 中,没有 readwritereadonly 属性。当定义一个存储的属性时,let 表示只读,var 表示可读可写。当定义一个计算出来的属性时,只提供 getter 方法,它就是只读的,同时提供 getter 和 setter 方法,它就是可读可写的。更多信息,可以查看 Properties 一章。

Copy 语法

在 Swift 中, Objective-C 的 copy 类型的属性被翻译为 @NSCopying。属性的类型必须遵从 NSCopying 协议。关于更多的信息,请查看 Attributes 一章。

实现 Core Data Managed Object 的子类

Core Data 提供了 NSManagedObject 子类属性的底层存储和实现。为你在 Core Data 数据模型中相应的属性或关系的子类的每一个类属性前面加上 @NSManaged 标记。就像 Objective-C 中的 @dynamic 标记,@NSManaged 告诉 Swift 编译器,一个属性的存储和实现将在运行时提供。然而,不像 @dynamic@NSManaged 标记,只有在 Core Data 的支持中可用。

Swift 的类是用命名空间管理的——他们用他们编译进的模块来区分(一般情况下是项目)。要使用 Swift 对 NSManagedObject 的子类到你自己的 Core Data 模型中,在 Class 文本框中加入你模型的前缀。


如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。
关注微信公众号
发现更多精彩
swift-cafe