函数数组不会保留其创建的值

时间:2017-10-11 07:54:01

标签: swift xcode function chain

我尝试用Manger管理我的功能。问题是功能代码更新,并且在我将功能添加到我的经理时保存。我尝试用这个例子来解释我的问题:

class QueueManager {

    typealias FunctionType = () -> ()

    private var functions = [(String, FunctionType)]()

    func add(funcName: String, function: FunctionType) -> QueueManager {
        functions.append(funcName, function)
        return self
    }

    func runFirst() -> Bool {
        guard functions.isEmpty == false else { return false }
        functions.first!.1()
        functions.removeFirst()
        return true
    }
}

然后我这样做:

let queueManager = QueueManger()

var value = 1

queueManager.add("simpleFunction"){
    print(value)
}

value = 2

queueManager.add("simpleFunction"){
    print(value)
}

queueManager.runFist()
queueManager.runFist()

结果是:

2 // Because value is 2 in both functions. But i added the function while value was 1??
2 

但我想要结果:

1
2

我做错了什么?提前谢谢!

编辑:非常简单的游乐场示例:

import UIKit


var str = "1"
func go() {
    print(str)
}

var array:[()->()] = []
array.append(go)

str = "2"

array.append(go)
array[0]()
array[1]()

// Output:
// 2
// 2

编辑2: 我知道2 2是我的代码的正确输出。但我希望将该功能保持在其创建状态。这有可能吗?

编辑3: 感谢您所有的帮助。但我认为我没有足够的解释我的问题来得到合适的答案。我想稍后调用一个带有参数的函数。我不想保留对参数值的引用。我只需要用这些参数值调用函数。

3 个答案:

答案 0 :(得分:1)

根据您的代码,显然结果应为:

2
2

因为您在编辑queueManager.runFirst()

之后正在调用value = 2两次

此外,如果add函数应包含functions.append((funcName, function)),那么我假设其function参数应为@escaping,如下所示:

class QueueManager {
    typealias FunctionType = () -> ()

    private var functions = [(String, FunctionType)]()

    func add(funcName: String, function: @escaping FunctionType) -> QueueManager {
        functions.append((funcName, function))
        return self
    }

    func runFirst() -> Bool {
        guard functions.isEmpty == false else { return false }
        functions.first!.1()
        functions.removeFirst()
        return true
    }
}

因此输出:

let queueManager = QueueManager()

var value = 1

queueManager.add(funcName: "simpleFunction") { 
    print(value)
}

queueManager.runFirst()

value = 2

queueManager.add(funcName: "simpleFunction"){
    print(value)
}

queueManager.runFirst()

应该是:

1
2

因为 - 很简单 - 在调用queueManager.runFirst()之前我调用了value = 2

同样的问题适用于您的简单示例:

var str = "1"
func go() {
    print(str)
}

var array:[()->()] = []
array.append(go)
array[0]()

str = "2"

array.append(go)
array[1]()

调用array.append(go)不会导致执行go(),您应该通过array[0]()调用它;由于您尝试打​​印相同变量(str)的值,因此always将为其打印最新值。如果要为每个函数单独保存每个值,您应该 - 以某种方式 - 声明多个变量(valuestr)。

答案 1 :(得分:1)

为了理解这里发生的事情,让我们一步一步看看:

  1. 将值1分配给值
  2. 将打印说明添加到QueueManager
  3. 将2分配给值
  4. 将打印说明添加到QueueManager
  5. 使用runFirst()
  6. 运行这些功能

    当您添加print(value)指令时,您将value作为参考类型传递。这会在变量functionsvalue之间创建一个强引用。因此,当您实际执行这些说明时,使用runFirst(),然后在该时间点使用value中存储的值。

    让我们探讨一下这个例子:

    var value = 5
    
    queueManager.add(funcName: "simpleFunction"){
        print(value)
    }
    
    queueManager.add(funcName: "simpleFunction"){
        print(value)
    }
    
    queueManager.runFirst()
    queueManager.runFirst()
    
    value = 10
    
    // output is 5  5
    

    在这种情况下,我们首先执行runFirst(),然后更新值。因此输出为5 5

    TL; DR - Pass By Reference导致函数打印变量value的当前值。

    编辑:将数据绑定到QueueManager中的函数,这将确保数据的当前值(在函数定义期间)与函数关联。

    class QueueManager {
    
        typealias FunctionType = (Int) -> ()
        private var functions = [(String, FunctionType, Int)]()
    
        func add(funcName: String, function: @escaping FunctionType, data: Int) -> QueueManager
        {
            functions.append((funcName, function, data))
            return self
        }
    
        func runFirst() -> Bool
        {
            guard functions.isEmpty == false else { return false }
            functions.first!.1(functions.first!.2)
            functions.removeFirst()
            return true
        }
    }
    
    let queueManager = QueueManager()
    
    // define you function within this closure
    let functionClosure: (Int) -> () = { (data) in
        print(data)
    }
    
    var value = 1
    queueManager.add(funcName: "simpleFunction", function: functionClosure, data: value)
    
    value = 2
    queueManager.add(funcName: "simpleFunction", function: functionClosure, data: value)
    
    queueManager.runFirst()
    queueManager.runFirst()
    

    输出:

    1
    2
    

答案 2 :(得分:1)

req.body.MediaUrl{N}

添加第一个simpleFunction后,您必须更新您的值。

游乐场输出:

[(" simpleFunction",(Function)),(" simpleFunction",(Function))]

1

[(" simpleFunction",(Function))]

2