概述
最近看到Ole Begemann的文章,先把要点列一下:
An instance method in Swift is just a type method that takes the instance as an argument and returns a function which will then be applied to the instance.
意思是说,实例方法是一种类型方法,该类型方法的参数是该类型实例,返回作用于该实例的函数。
如果有ObjC经验的,会将type method和ObjC的类方法联系在一起——并且,官方文档上也是这么类比的。但是,却没有指出instance和type method这种”本质”的联系。
Curried function 柯里化函数
柯里化函数是将多参数的函数转化为单个参数(首个参数)的函数,并返回接受剩余参数且返回结果的新函数。举个SwiftProgrammingLanguage中的例子:
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
let incrementByTwenty = makeIncrementer(forIncrement: 20)
Instance Methods 实例方法本质
先把oleb中的代码挪过来:
class BankAccount {
var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
}
//1
let account = BankAccount()
account.deposit(100) // balance is now 100
//2
let depositor = BankAccount.deposit
depositor(account)(100) // balance is now 200
//3
BankAccount.deposit(account)(100) // balance is now 300
1是我们通常使用instance method的场景,2中则是先定义了一个function,该函数以BankAccount实例为参数,返回一个带参数的新函数。其中,depositor的类型是: BankAccount -> (Double) -> ()
。 3则是2的直接调用形式。
Target-Action的Swift实现
Target-Action是iOS/Cocoa开发中最常见的模式。ObjC时代,该模式的实现依赖于ObjC的runtime特性。在Swift中,使用selector需要添加@objc
关键字。下面采用curried function的概念,
实现一个纯Swift版本的target-action。
protocol TargetAction {
func performAction()
}
struct TargetActionWrapper<T: AnyObject> : TargetAction {
weak var target: T?
let action: (T) -> () -> ()
func performAction() -> () {
if let t = target {
action(t)()
}
}
}
enum ControlEvent {
case TouchUpInside
case ValueChanged
// ...
}
class Control {
var actions = [ControlEvent: TargetAction]()
func setTarget<T: AnyObject>(target: T, action: @escaping (T) -> () -> (), controlEvent: ControlEvent) {
actions[controlEvent] = TargetActionWrapper(target: target, action: action)
}
func removeTargetForControlEvent(controlEvent: ControlEvent) {
actions[controlEvent] = nil
}
func performActionForControlEvent(controlEvent: ControlEvent) {
actions[controlEvent]?.performAction()
}
}
class MyViewController {
let button = Control()
func viewDidLoad() {
button.setTarget(self, action: MyViewController.onButtonTap, controlEvent: .TouchUpInside)
}
func onButtonTap() {
println("Button was tapped")
}
}
注意,escaping必不可少,因为closure作为一个参数,并且该closure在函数返回后才会被执行——这也就是escaping closure。
最后,文中代码都可以在Xcode8.2.1, Swift3正确运行。
补充说明
另外,查阅 SwiftProgrammingLanguage 修改历史, 发现在1.1版本中引入的curried function描述,在2.2版本中移除了。
Comments