混用Swift和objc - 基于objc写Swift

Swift 与 objc 的互操作性让你可以基于 objc 创建类和协议,这些类和协议就可以用强大的 Swift 来编写。

继承 objc 类

要在 Swift 中继承 objc 的类,只要在 Swift 类名后写上:,并跟上要继承的 objc 的类名:

1
2
3
4
import UIKit
class MySwiftViewController: UIViewController {
// define the class
}

要重写父类方法时,使用override修饰符。

NSCoding

NSCoding协议要求实现必须的初始器init(coder:)encode(with:),实现这个协议的类的子类如果有自定义的初始器或没有初始值的属性时,也必须实现这个方法。

对于从 Storyboard 加载的、用NSUserDefaultsNSKeyedArchiver类归档到磁盘的对象,必须要提供这类初始器的实现。对于不能以这种方式初始化的类型,就不必须实现初始器。

使用协议

协议跟在父类,用,分隔。

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

对比于 objc 中声明遵从协议的类型:id<SomeProtocol>id<SomeProtocol, AnotherProtocol>,在 Swift 中:

1
2
var textFieldDelegate: UITextFieldDelegate
var tableViewController: UITableViewDataSource & UITableViewDelegate

由于在 Swift 中,类和协议的命名空间是统一的,objc 中的NSObject协议对应于 Swift 中的NSObjectProtocol协议。

编写构造器和析构器

Swift 的编译器保证构造器让所有属性都初始化。

如果想在对象回收前做些清理工作,可以实现析构器。父类的析构器将在子类析构器之后执行。

通过 objc APIs 使用 Swift 的类名

Swift 类的命名空间是基于它们编译所在的模块,所以可以通过模块来区分相同名字的类。

1
let myPersonClass: AnyClass? = NSClassFromString("MyGreatApp.Person")

与 Interface Builder 集成

使用 Outlets 和 Actions

在 Swift 中,通过@IBOutlet@IBAction来使用 outlets 和 actions。

Swift 中的 outlet 需要定义为隐式解包可选类型,这样就可以让 storyboard 在初始化后,在运行时连接 outlets。

1
2
3
4
5
6
7
class MyViewController: UIViewController {
@IBOutlet weak var button: UIButton!
@IBOutlet var textFields: [UITextField]!
@IBAction func buttonTapped(sender: AnyObject) {
print("button tapped!")
}
}

实时渲染

为了在 IB 中使用实时的、交互式的自定义视图设计,可以用两个不同的属性——@IBDesignable@IBInspectable。创建继承自UIView的自定义 view 时,可以在类定义之前添加@IBDesignable,这样,把自定义 view 添加到 IB 中时,IB 会渲染你的 view。

可以在属性前添加@IBInspectable,使之与 user defined runtime 属性兼容。

1
2
3
4
5
6
@IBDesignable
class MyCustomView: UIView {
@IBInspectable var textColor: UIColor
@IBInspectable var iconHeight: CGFloat
// ...
}

指定 property 的属性

Strong 与 Weak

Swift 中使用weak关键字来声明弱引用,只能用在可选类型的 property。

读写与只读

Swift 中没有readwritereadonly属性,而是使用letvar来对应只读和读写的存储变量。对于计算性变量,只提供 getter 使它只读,提供 getter 和 setter 使之可以读写。

拷贝语义

在 Swift 中,objc 的copy属性翻译成@NSCopying,这个类型必须实现NSCopying协议。

实现 Core Data Managed Object 的子类

在 managed object 的子类的属性前添加@NSManaged告诉 Swift 编译器,Core Data 会在运行时提供其实现和存储。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Person+CoreDataClass.swift
import CoreData
class Person: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
}
// Person+CoreDataProperties.swift
extension Person {
@NSManaged var name: String
@NSManaged var friends: NSSet
}

声明协议

要创建可以被 objc 使用的 Swift 协议,使用@objc标记protocol的声明。

1
2
3
4
5
6
7
8
import UIKit
@objc protocol MyCustomProtocol {
var people: [Person] { get }
func tableView(_ tableView: UITableView, configure cell: UITableViewCell, forPerson person: Person)
@objc optional func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forPerson person: Person)
}

可选的协议要标记为@objcoptional。objc 类实现 Swift 定义的协议和实现 objc 的协议是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@interface MyCustomController: UIViewController <MyCustomProtocol>
@property (nonatomic, strong) NSArray<Person *> *people;
@end
@implementation MyCustomController
@synthesize people;
- (void)tableView:(UITableView *)tableView
configure:(UITableViewCell *)cell
forPerson:(Person *)person
{
// Configure cell
}
@end

参考