swift closure capture list

最近用swift写app,发现很多特性都很有意思,并且很实用,比如closure, Optional类型等等。closure可以看做是objc中的block,c++和python中的lambda,熟悉函数式编程的同学可以很快上手。

在进行异步的网络调用时,需要把closure作为参数传递给执行网络请求的函数。比如NSURLSessionDataTask,需要把网络请求执行完毕之后的逻辑写在completionHandler里面。

很多时候我们需要在UIViewContronller里面来执行网络请求,请求完成后再更新ui上的数据,那么这里的closure中肯定会访问到self.someProperty或者self.someMethod()。这样closure本身就有一个对self的强引用(strong referrence)。另外,closure在swift中跟class一样,也是引用类型(referrence type)。这样一来closure和self就互相引用,产生strong referrence cycle。closure和self都无法被deallocate,造成资源的浪费。

为了解决这个问题,就要用到closure的捕获列表。语法如下:

捕获列表中可以使用两种类型:unowned和weak。因为一开始没有弄清楚这两种的区别,直接在代码中使用了unowned self,造成app在运行过程中出现“attempted to retain deallocated object”错误。

这段代码中第29行可以看到,在closure中访问self时并没有判断self是否还存在。所以当网络请求执行完再更新ui的时候就会出现“attempted to retain deallocated object”。unowned和weak的一个区别在于weak self是optional类型。这样一来就可以利用optional chaining来做一个保护机制。正确的实现代码如下:

这里的29行使用了swift中的if let结构,如果photoView是有值的,则继续执行后面的逻辑,否则会走到else分支中。这样便很好的解决了上面的问题。

参考:

  1. StackOverflow – Shall we always use [unowned self] inside closure in Swift?
  2. Automatic Reference Counting
  3. Swift Optionals: When to use if let, when ? and !, when as? and as

发表评论

电子邮件地址不会被公开。 必填项已用*标注