使用选择器和键路径与动态 Objective-C API 进行交互。
概览
一些 Objective-C API (如 target-action) 接受将方法或属性名称作为参数,然后使用这些名称来动态调用或访问相应的方法或属性。在 Swift 中,你可以分别使用 #selector
和 #key
表达式,将这些方法或属性名称表示为选择器或键路径。
使用选择器安排对 Objective-C 方法的调用
在 Objective-C 中,选择器是一种引用 Objective-C 方法名称的类型。在 Swift 中,Objective-C 选择器通过 Selector
(英文) 结构来表示,你可以使用 #selector
表达式来创建它们。
在 Swift 中,你可以通过将方法名称放在 #selector
表达式中来为 Objective-C 方法创建选择器:#selector(My
。要为属性的 Objective-C getter 或 setter 方法构建选择器,应使用 getter:
或 setter:
标签为属性名称添加前缀,例如:#selector(getter: My
。以下示例演示了将一个选择器用作 target-action 模式的一部分来调用一个用于响应 touch
(英文) 事件的方法。
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
let action = #selector(MyViewController.tappedButton)
myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
}
func tappedButton(_ sender: UIButton?) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
如果你需要分清不同的重载函数,应使用带括号的表达式及 as
运算符,使 #selector
表达式明确地引用特定的重载。
使用键路径动态访问 Objective-C 属性
在 Objective-C 中,键是一个用于标识对象的特定属性的字符串。键路径是一串用句点分隔的键,用于指定要遍历的一系列对象属性。键和键路径常常用于键值编码 (KVC),这是一种利用字符串标识符间接访问对象的属性和关系的机制。
重要信息
Objective-C 键路径与 Swift 中的键路径表达式既有区别又有联系。有关键路径表达式的信息,请参阅“Swift 编程语言 (Swift 4.1) (英文)”中的“键路径表达式 (英文)”。
你可以使用 #key
字符串表达式来创建由编译器检查的键和键路径,供 value(for
(英文) 和 value(for
(英文) 等 KVC 方法使用。#key
字符串表达式接受方法或属性的链式引用;同时亦支持链中的可选值链式调用,如 #key
。利用 #key
字符串表达式创建的键路径不会向接受键路径的 API 传递与所引用的属性或方法相关的类型信息。
以下示例定义了一个 Person
类,创建了该类的两个实例,然后使用多个 #key
字符串表达式来访问各个属性以及这些属性的属性:
class Person: NSObject {
var name: String
var friends: [Person] = []
var bestFriend: Person? = nil
init(name: String) {
self.name = name
}
}
let gabrielle = Person(name: "Gabrielle")
let jim = Person(name: "Jim")
let yuanyuan = Person(name: "Yuanyuan")
gabrielle.friends = [jim, yuanyuan]
gabrielle.bestFriend = yuanyuan
#keyPath(Person.name)
// "name"
gabrielle.value(forKey: #keyPath(Person.name))
// "Gabrielle"
#keyPath(Person.bestFriend.name)
// "bestFriend.name"
gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))
// "Yuanyuan"
#keyPath(Person.friends.name)
// "friends.name"
gabrielle.value(forKeyPath: #keyPath(Person.friends.name))
// ["Yuanyuan", "Jim"]