【问题标题】:Swift closure capture array by referenceSwift 闭包通过引用捕获数组
【发布时间】:2018-01-04 02:28:15
【问题描述】:

在 Swift 中,集合默认是按值传递的,我们可以使用 inout 使其在函数参数中通过引用传递,但我们如何在闭包捕获变量中做到这一点?

var list = [1, 2, 3]
func edit(inout list: [Int]) {
    list.append(4)
    dispatch_async(dispatch_get_main_queue()) {
        list.append(5)
    }
}
edit(&list)
...// after dispatch_async was executed 
NSLog("\(list)")

结果将是 [1, 2, 3, 4]

如何修改闭包内的原始变量 ()?

更新:

实际上,我有一个解决方法来处理这种情况,方法是将数组放入一个对象中,这样我就可以通过引用将该对象传递给函数,并且我们可以在函数内部修改相同的数组实例。但我想看看任何巧妙的存档方法

【问题讨论】:

    标签: swift closures pass-by-reference pass-by-value inout


    【解决方案1】:

    要从闭包中获得变量转义,您需要@escaping,请检查this。一种解决方法是将完成函数作为参数而不是 inout 变量。

    class MyClass {
        static func edit(_ list: [Int], _ completion: @escaping ([Int]) -> ()) {
            var list = list
            list.append(4)
            DispatchQueue.main.async() {
                list.append(5)
                completion(list)
            }
        }
    }
    
    var myList = [1, 2, 3]
    MyClass.edit(myList) { (list) in
        myList = list
        print("My list after editing: \(myList)")
    }
    print("My list without editing: \(myList)")
    

    注意:以上示例适用于 Swift 3,其中 inout 参数不允许在闭包中捕获。根据您的帖子,您可能使用的是较低版本的 Swift,您可以使用 inout 而不是设置 list 的可变副本:var list = list。但是,逻辑非常相似。

    更多信息请查看Limiting inout capture to @noescape contexts in Swift evolution:

    当闭包捕获inout 参数并转义时,Swift 的行为 它们的封闭上下文是混淆的常见来源。我们应该 禁止隐式捕获 inout 参数,@noescape 除外 关闭。

    【讨论】:

    • 感谢您的回复,但是否有机会在不访问函数内部的任何实例变量的情况下实现它?您可以将其视为静态函数
    • 谢谢,您的回答是一种取回数组新副本的方法,我们可以在完成闭包中更新实例数组变量。但我想知道在传递给函数后“直接”修改原始数组的任何机会。抱歉我在问题中的错误解释。我已经尝试过您的代码,全局 list 变量的结果仍然是 [1, 2, 3]
    • 我再次更新了我的答案以使用 myList 而不是 list 以减少混乱。要获得编辑后的myList,您需要等到编辑完成。如果您想直接编辑myList,只需将其作为您的类中的类级变量并在闭包中使用self.myList 之类的东西。由于您一开始就不想采用这种方法,因此您不能直接修改myList。出于原因,请查看我在答案中提供的链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    相关资源
    最近更新 更多