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还活着的时候使用。哦,好的,最后一件事:内存泄漏有什么不好的。。我可以忽略无主的或弱的,只留下它。通过向闭包传递强引用,会导致内存泄漏,而这个传递的东西恰好也会使闭包保持活动状态。如果你忽略内存泄漏,你的应用程序最终会耗尽内存。对于小而简单的类,这一点并不明显。但是,例如,如果你泄露了“图像”对象或其他资源密集型的东西,那么系统将无法恢复这些内存,并最终杀死你的应用程序。哦,好的。编译器有没有一种简单的方法来检测内存泄漏,这样我们就可以返回并添加弱/无内存?