委托与回调函数

class ScrollViewCtrl: UIViewController, UIScrollViewDelegate {
  //some code
  override func viewDidLoad() {
    super.viewDidLoad()
    let scrollView = UIScrollView()
    scrollView.delegate = self
  }

  func scrollViewDidScroll(scrollView: UIScrollView) {
    //do something
  }
  //some code
}

这一段Swift代码稀疏平常,平常到可能有的同学从未想过这段代码背后做了什么。这里其实使用了一个同样稀疏平常却广为流传的设计模式——delegate模式。Delegate模式是在Cocoa开发中随处可见的一种设计模式,几乎贯穿于整个Cocoa框架。尤其是在我们最常使用的UIKit中,控制各类UI组件的最常用手段就是delegate跟Target-action(目标-动作,类似于一个监听事件)。至于回调函数么,其实跟委托没什么关系,然而曾经年少无知的我对这两个概念十分模糊,我想可能现在也有很多同学感到一头雾水,所以今天我想针对委托模式和回调函数分别讲一讲自己的理解,如有疏漏,欢迎各位批评指正。

我们先回到开头的代码,看看到底发生了什么。ScrollViewCtrl是一个控制器,它confirm to(遵守,大致就是其他语言中实现一个接口的意思)UIScrollViewDelegate这个protocol(协议)。虽然Swift的委托实现跟协议息息相关,但我在这里不准备过多讨论协议的细节内容,只要知道它类似于其他语言的interface(接口)就可以了,只是Swift中的protocol不仅可以被class遵守, 还可以被structenum遵守。

接着往下说,一开始我初始化了一个UIScrollView,并把它的delegate属性设置成self(即ScrollViewCtrl的一个实例)。然后在ScrollViewCtrl中写了一个scrollViewDidScroll方法。这样在这个scrollView滑动的时候就会执行scrollViewDidScroll里面的代码了。

讲到这里我想大部分人还是不明白委托到底是怎么回事,因为我在这里只是使用了委托,具体的委托实现是UIKit框架写好的,这样对于理解委托来说无异于隔靴搔痒,所以下面我来实现一个完整的委托。

//创建
protocol MyDelegate: class {
  func delegateMethod()
}

class MyClass {
  weak var delegate: MyDelegate!
  
  func doSomethingWithAdditionalInfo() {
    //...
    delegate.delegateMethod()
  }
}

//使用
class MyCtrl: UIViewController, MyDelegate {
  var myInstance: MyClass!
  override func viewDidLoad() {
    super.viewDidLoad()

    myInstance = MyClass()
    myInstance.delegate = self
    myInstance.doSomethingWithAdditionalInfo()
  }

  func delegateMethod() {
    println("Run")
  }
}

上面的代码是我随手写的,没跑过,理论上会输出"Run",各位可以试一试。这其实就是一个完整的委托模式了,当然在真实的情况下,一般doSomethingWithAdditionalInfo会在某个特定的时机运行delegate.delegateMethod这方法,譬如它可能会是个发送异步网络请求取数据的方法,然后在取到数据后调用delegate.delegateMethod,而取到数据后要做什么操作可以延迟到使用的时候再定义,即由使用者自行定义delegateMethod的具体操作。这是一种良好的解耦,非常适合在框架中使用。

委托说完了,那什么是回调函数呢?其实回调函数做的事情跟委托很类似。不同的是,回调函数通过传递函数来实现延迟定义操作(在C这样的过程式语言中,需要通过函数指针作为参数传递来调用函数,而在支持高阶函数的函数式语言中,可以直接以函数为参数传递进行操作)。Swift对函数式编程的支持非常到位,所以可以轻松编写回调函数。依然以上面那段代码实现的功能为例,这次我们只要:

//创建
func doSomethingWithAdditionalOperation(additionalOperation: () -> ()) {
    //...
    additionalOperation()
  }

//使用
class MyCtrl: UIViewController, MyDelegate {
  override func viewDidLoad() {
    super.viewDidLoad()
    
    doSomethingWithAdditionalOperation {
      println("Run")
    }
  }
}

你可能感兴趣的:(委托与回调函数)