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

Array of functions don't keep their values from their creation

我尝试使用 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: 感谢您所有的帮助。但我认为我未能充分解释我的问题以获得合适的答案。我想稍后用它的参数调用一个函数。我不想保留对参数值的引用。我只需要用这些参数值调用函数。

根据你的代码,显然结果应该是:

2
2

因为您在编辑 value = 2

之后 调用了 queueManager.runFirst() 两次

此外,如果 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

因为 - 简单 - 我在 调用 value = 2

之前调用了 queueManager.runFirst()

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

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]()调用;由于您正在尝试打印 same 变量 (str) 的值,它将 always 打印它的最新值。如果你想为每个函数分别保存每个值,你应该 - 以某种方式 - 声明多个变量(valuestr)。

为了了解这里发生了什么,让我们一步一步地看一下:

  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 - 引用传递导致函数打印变量 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
import UIKit

var str = "Hello, playground"

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 }
        print(functions)
        functions.first!.1()
        functions.removeFirst()
        return true
    }
}

var value = 1
let queueManager = QueueManager()

func simpleFunction(_ value: AnyObject){
    print(value)
}

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

queueManager.add(funcName: "simpleFunction"){
    value = 2
    simpleFunction(value as AnyObject)
}

queueManager.runFirst()
queueManager.runFirst()

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

游乐场输出:

[("simpleFunction", (函数)), ("simpleFunction", (函数))]

1

[("simpleFunction", (函数))]

2