加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Swift中实例方法柯里化及自己实现Target-action模式

发布时间:2020-12-14 01:32:51 所属栏目:百科 来源:网络整理
导读:方法柯里化 ,就是把接受多个参数的方法变换成接受第一个参数的方法,并且返回接受余下的参数并且返回结果的新方法。 可以通过柯里化一个方法模板来避免写出很多的重复代码,方便维护。 举一个实际应用时候的例子: button.addTarget(self,action: "onClickB

方法柯里化,就是把接受多个参数的方法变换成接受第一个参数的方法,并且返回接受余下的参数并且返回结果的新方法。

可以通过柯里化一个方法模板来避免写出很多的重复代码,方便维护。

举一个实际应用时候的例子:

button.addTarget(self,action: "onClickBtn:",forControlEvents: .TouchDown)
func onClickBtn(sender: UIButton){
    println("点击了Button");
}
在Swift 中Selector 只能使用字符串在生成。这面临一个很严重的问题,就是难以重构,并且无法在编译期间进行检查,其实这是十分危险的行为。

但是target-action 又是Cocoa 中如此重要的一种设计模式,无论如何我们都想安全地使用的话,应该怎么办呢?一种可能的解决方式就是利用方法的柯里化

Ole Begemann 在这篇帖子里提到了一种很好封装,这为我们如何借助柯里化,安全地改造和利用target-action 提供了不少思路。

示例一

假设现在我们有一个简单的银行账户类BankAccount

class BankAccount {
    var balance: Double = 0.0

    func deposit(amount: Double) {
        balance += amount
    }
}
我们可以明显的创建这个类的一个实例,然后通过这个实例调用deposit()方法:
let account = BankAccount()
account.deposit(100) // balance is now 100

没错,上面非常简单。但我们也可以这样做:
let depositor = BankAccount.deposit
depositor(account)(100) // balance is now 200

这样做和上面的写法是等价的。 等等,出现什么了,为什么会这样?我们首先为方法分配了一个变量。注意:BankAccount.deposit缺少一个括号,这里我们并不是调用这个方法(这将产生一个错误,因为你不能调用该类型的实例方法),而仅仅是引用它,这更像是C语言中的函数指针。第二步就是调用存储在depositor变量中的函数。这个变量的类型如下所示:

let depositor: BankAccount -> (Double) -> ()

换句话说,第一部分: 这个函数一个参数一个BankAccount的实例并返回另一个函数。第二部分:后面这个函数接收一个Double类型的参数,并返回空。在第二部分中,你应该理解实例方法deposit()的签名。


我希望你能看到在Swift中一个实例方法是一种简单的方法,这个方法其实就是将实例作为参数,然后返回一个函数,将其应用到实例中。

当然,我们也可以用一行代码做到这点,这使得类型方法和实例方法之间的关系更加清晰:

BankAccount.deposit(account)(100) // balance is now 300

通过将实例account作为参数传给 BankAccount.deposit(),该实例被绑定到方法上,然后我们传入参数,调用这个方法。非常棒,对不?

示例二

Swift中实现Target-Action

Christoffer Lern? 在开发者论坛上展示了如何使用纯swift语言将Swift的类型系统这一特点应用到target-action模式中。不同于Cocoa种的常见实现,Christoffer的解决方案并没用依赖OC中的动态消息调度机制。它是完全类型安全的,因为其并不依赖selectors。

这种模式往往比用闭包实现回调更好,特别是当在一个不确定的时间接收对象必须使用闭包。使用闭包经常使API的调用者做额外的工作来防止引用循环。使用target-action模式,提供API的对象可以做内部类型转换,使得在调用方面让代码更加简洁。

例如,一个使用Target-Action控制可能是这样(采纳自a dev forums post by Jens Jakob Jensen)

Update July 29,2014: Made the action property in TargetActionWrapper non-optional. target must be optional because it is weak.

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: (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")
    }
}

Target-action:目标-动作模式,贯穿于iOS开发始终。我们自己在 Swift中实现了这一模式,是不是略叼~~! :-)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读