克服你的[弱者]

我知道。 今天是星期三。 我通常在星期五发布。 但是金莺正在崩溃和燃烧,所以我的夜晚突然变得不那么忙了。

几周前,我写了关于自动引用计数和强引用周期与弱引用周期的文章。 仔细研究这个问题确实使我在脑海中强化了这个话题。 我真正在努力的是:

  var someFunction:()->字符串= {[弱自我] 
返回“嗨!我是帕特!”
}

…这他妈到底是什么? [弱者]? 我很害怕。

好吧,当我第一次学习它时,有一些信息让我感到惊讶:闭包是引用类型。 是的 谁知道? 你可能知道。 我没! 我一直在假设闭包是值类型,因为,就像您知道的那样。 迅速。 Swift❤值类型。 但是不。 Swift闭包确实是引用类型。

下面的示例我来自开发人员Bob,因为它很好地说明了将闭包作为引用类型。

如果我们有一个闭包数组,然后将闭包附加到该数组:

  var闭合数组:[()->()] = [] 
变量i = 0
  _ in 1 ... 5 { 
closureArray.append {print(i)}
我+ = 1
}

您可能希望当我们在closureArray中调用每个单独的闭包时,它会打印出1到5的数字。但是,事实并非如此。 而是,每个闭合将打印出数字5。为什么!?

因为傻瓜,我们正在使用引用类型。 我们所有的五个闭包都引用内存中的同一点。 当我们为这些闭包之一更改“ i”的值时,我们为所有这些闭包更改了它。 当实例化每个闭包时,我们不会在闭包中为石头设置“ i”的值。 我们只是告诉闭包每次调用闭包时都引用i。

幸运的是,Swift向导的神奇顺序使我们可以解决。 如果我们像这样实例化关闭:

  var i = 0 
  _ in 1 ... 5 { 
ClosureArray.append {[i] in
打印(i)
}
i + = 1
}

这将给我们我们所期望的。 如果我们调用closureArray [0](),则控制台将输出“ 1”。 closureArray [1]打印出“ 2”,依此类推。 那有什么不同呢? 如果您看,我们将i变量放在方括号中。 但是,那是做什么的呢?

简单。 它复制i引用的值。 就像值类型一样!!! 整齐。 因此,现在,闭包不再引用其范围之外的变量,而是直接引用实例化的值。 现在您有了一个不错的,自包含的闭包,其行为与您期望的一样。 我们称其为“捕获列表”。

因此,很高兴知道这一点,但这在现实世界中如何影响我们? 这与[弱者]有什么关系?

假设我们有一个带有几个属性的类:

 狗类{ 
  var name =“ Maizie” 
  var bark:(()->())吗? 
 在里面() { 
 树皮= {print(“ Woof!我叫\(self.name)!”)} 
  } 
  deinit { 
 打印(“再见狗!”) 
  } 
  } 
  var maizie = Dog() 

“再见!”将永远不会打印出来(注意:您不能在Swift操场上进行真正的测试。操场会使实例异常自然地活着,以实现使它们如此出色的实时反馈。)为什么不呢? 让我们考虑一下。 您有一个称为“ bark”的引用类型闭包。 在闭包内,我们在Dog类中引用另一个属性:name。 因此,我们增加了参考数量,但没有任何办法删除该参考。 如果您还记得两周前的话,这种确切的情况称为“内存泄漏”。 即使没有使用内存,我们也有一个引用来保持内存。 我们可以通过声明一个弱变量来解决此问题。 不过,这次,我们将使用捕获列表来做到这一点:

 树皮= {[弱自我] 
print(“ Woof!我叫\(self.name)!”)
}

现在,我们不是在闭包范围之外进行引用,而是制作了一个自我副本。 新的自我在这种封闭中生存和死亡。 它不会使我们的Dog类实例异常活跃。

所以你有它。 [弱者]。 当我第一次听到它时,所有这些ARC的东西都会让我感到困惑,但是我保证,如果您重复几次,它很快就会变得有意义。

感谢您的阅读,并确保留下问题和评论! 下周,我认为我将介绍一些很酷的内容:对API进行多个异步调用,甚至可能对PromiseKit有所了解。