Swift 闭包如何捕获数据?
我不理解闭包捕获数据这一概念。。有人能用闭包编写一个示例代码来说明数据是如何从不被破坏的吗。。我已经阅读了苹果的文档,但我仍然感到困惑。还有,“无主”和“弱”对关闭有什么影响Swift 闭包如何捕获数据?,swift,Swift,我不理解闭包捕获数据这一概念。。有人能用闭包编写一个示例代码来说明数据是如何从不被破坏的吗。。我已经阅读了苹果的文档,但我仍然感到困惑。还有,“无主”和“弱”对关闭有什么影响 class TableViewController: UITableViewController { var allWords = [String]() var usedWords = [String]() override func viewDidLoad() { super.viewDidLoad()
class TableViewController: UITableViewController {
var allWords = [String]()
var usedWords = [String]()
override func viewDidLoad() {
super.viewDidLoad()
if let allWordsPath = Bundle.main.path(forResource: "start", ofType: "txt"){
if let startWords = try? String(contentsOfFile: allWordsPath){
allWords = startWords.components(separatedBy: "\n")
}else{
allWords = ["Cake"]
}
startGame()
}
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Make Word", style: .plain, target: self, action: #selector (makeWord))
}
func startGame(){
allWords = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: allWords) as! [String]
title = allWords[0]
usedWords.removeAll(keepingCapacity: true)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usedWords.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Word", for: indexPath)
cell.textLabel?.text = usedWords[indexPath.row]
return cell
}
func makeWord() {
let ac = UIAlertController(title: "Add Word", message: nil, preferredStyle: .alert)
ac.addTextField(configurationHandler: nil)
let submit = UIAlertAction(title: "Submit", style: .default){ [unowned self,ac]
(action: UIAlertAction!) in
let answer = ac.textFields?[0]
self.submit(answer: (answer?.text)!)
}
ac.addAction(submit)
present(ac,animated: true)
}
var number = 10
func submit(answer: String){
usedWords.append(answer)
tableView.reloadData()
}
如果我们没有明确地分配物品,无主在这里是如何工作的?您应该首先搜索强、弱和无主之间的区别。关于这个问题,这里有很多答案 无论如何,在这种特殊情况下: 您的闭包包含以下代码:
[unowned self,ac]
这称为“捕获列表”。它指示在创建块时应通过值“捕获”的内容。(如果不在此处指定它们,并且在块之后的某个位置更改值,则块内的值也将更改)
self无主且不需要解除分配的原因是因为无主意味着:
“不要担心此变量的内存管理,它将始终
在我的结束期间有一个值“
所以,回到unowned self,您应该从闭包中声明弱或unowned self变量的原因是,如果不是,您将创建一个retain循环。只要有东西在引用它们,就不能释放它们。因此,在本例中,TableViewController使闭包保持活动状态,而闭包使TableViewController保持活动状态。因此,由于它们相互引用,因此没有一个能够正确地解除分配。->内存泄漏
所以我们可以得出这样的结论:自我要么是软弱的,要么是无主的。对于本例中的所有意图和目的,它们完全相同。它们都是为了“打破保留周期”,通过消除关闭保持自我存活的能力。那么你问谁呢?你的结束并不重要。但是,在你的结束之外思考。您的TableViewController正在调用您的闭包,因此,既然这里没有发生奇怪的事情,我们可以安全地假设,如果显示警报,它必须最终显示在您的TableViewController上。因此,一旦您解除警报或其他警报,您的TableViewController将继续正常工作。但是,一旦您解除TableViewController,self将被解除分配(因为闭包将其引用为无主),但此时无法显示警报。但是,如果您做了一些奇怪的事情,使您的TableViewController在警报仍在显示时被解除,那么一旦用户“提交”,您的应用程序将崩溃。因为通过声明你的变量为unowned,你基本上向你的闭包保证了它不必担心自我实体,因为只要你的闭包还活着,它就会一直存在。看看这个。我正在创建两个相同类型的对象。一个对闭包的引用保留了它自己,因此即使创建它的函数超出了范围,对象和闭包也会相互保留,永远不会被释放。第二个对象的闭包对该对象的引用较弱,因此当创建对象的函数超出范围时,引用计数为0,当它被释放时,它也会释放闭包
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
class B {
deinit {
print("\(name) deinit")
}
var name: String
init(name: String) {
self.name = name
}
var zort: (() -> ())?
func someMethod() {
print("")
}
}
func createStuffThatNeverGoesAway() {
var b: B = B(name: "bad");
b.zort = {
b.someMethod()
}
}
func createStuffThatGoesAway() {
var b: B = B(name: "good");
b.zort = { [weak b] in
b?.someMethod()
}
}
createStuffThatNeverGoesAway()
createStuffThatGoesAway()
输出:
good deinit
我不明白他的例子。检查我的答案。顺便说一句,闭包不能确保数据永远不会被破坏。它们只允许您指定应该如何处理数据,以及在数据被破坏时应该做什么。将一个变量设置为“弱”,然后在闭包内简单地检查它是完全有效的。因此,基本上,如果我们不设置unowned或weak,闭包内的属性将受到外部更改的影响?或者它们只是为了解除分配的目的而需要……而且,viewController的所有属性都有对自身的引用,所以它们是如何解除分配的。你在混合东西。“无主”或“弱”与是否在外部修改无关。首先,括号内的内容[属性]不会受到外部内容的影响。第二,为了交易的目的,需要弱小和无主。为了避免保留循环,第三,viewController中的所有属性都由viewController本身(即“自身”)保持活动状态。解除分配viewcontroller时会解除分配它们,而解除分配viewcontroller时会发生这种情况。这与闭包无关,你只需要确保闭包只在VC还活着的时候使用。哦,好的,最后一件事:内存泄漏有什么不好的。。我可以忽略无主的或弱的,只留下它。通过向闭包传递强引用,会导致内存泄漏,而这个传递的东西恰好也会使闭包保持活动状态。如果你忽略内存泄漏,你的应用程序最终会耗尽内存。对于小而简单的类,这一点并不明显。但是,例如,如果你泄露了“图像”对象或其他资源密集型的东西,那么系统将无法恢复这些内存,并最终杀死你的应用程序。哦,好的。编译器有没有一种简单的方法来检测内存泄漏,这样我们就可以返回并添加弱/无内存?