我可以在数组中存储方法吗?

时间:2014-11-13 09:38:25

标签: methods swift

请考虑以下代码:

class Test {

    func func1(arg1: Int) -> Void {
        println(arg1)
    }

    var funcArr: Array< (Int) -> Void > = [func1] // (!) 'Int' is not a subtype of 'Test'
}

我正在尝试将方法func1存储在一个数组中,但正如您所看到的,这似乎不起作用,因为func1假定只接受{{1}类型的参数}。我认为这与需要与对象关联的方法有关。

有关更多说明,请查看以下代码,我让swift推断出数组的类型:

Test

此问题的可能解决方法是将class Test { func func1(arg1: Int) -> Void { println(arg1) } var funcArr = [func1] } Test().funcArr[0](Test()) // Compiles, but nothing gets printed. Test().funcArr[0](1) // (!) Type 'Test' does not conform to protocol 'IntegerLiteralConvertible' Test().func1(1) // Prints '1' 移到类之外,如下所示:

func1

这适用于这个简单的例子,但是当我真正需要在函数中对func func1(arg1: Int) -> Void { println(arg1) } class Test { var funcArr = [func1] } Test().funcArr[0](1) // Prints '1' 类型的Object进行操作时,它不太理想。我当然可以在函数中添加另一个参数来将Test的实例传递给函数,但这看起来很笨拙。

我有什么方法可以在数组中存储方法吗?

最终,我希望能够做的是Test,并且该功能可以作为属于testObject.funcArr[someInt](someParam)的方法。任何聪明的解决方法当然也是受欢迎的。

2 个答案:

答案 0 :(得分:4)

Instance methods in swift are just curried functions,第一个参数隐含地是类的实例(即self)。这就是为什么这两者是等价的:

Test().func1(0)
Test.func1(Test())(0)

因此,当您尝试将该函数放入数组中时,您会陶醉它的真实性质:func1上的方法Test实际上就是这个类方法:

class func1(self_: Test)(arg1: Int)

因此,当您仅提及func1(没有“实例上下文”)时,它的类型为Test -> Int -> Void,而不是预期的Int -> Void,这就是您收到错误的原因

  

Int不是Test

的子类型

所以真正的问题是,当你将方法存储在funcArr中时,实例还不知道(或者如果你愿意,你将在类级别引用该函数)。您可以使用计算属性解决此问题:

var funcArr: [Int -> Void] { return [func1] } // use a computed property

或者另一个有价值的选择可能只是承认func1的真实类型并明确传递实例。 E.g。

...
var funcArr = [func1]
...

let test = Test()
let func1 = test.funcArr[0]
func1(test)(0) // prints 0

更新

受到其他Q / A(Make self weak in methods in Swift)的启发,我想出了一个存储方法参考的类似解决方案。

func weakRef<T: AnyObject, A, B>(weakSelf: T, method: T -> A -> B) -> A -> B {
    return { [unowned weakSelf] in { a in method(weakSelf)(a) } }()
}

class Test {
    var methodRefs: [Int -> Void] = []

    init() {
        methodRefs.append(weakRef(self, Test.func1))
    }

    func func1(arg1: Int) {
        println(arg1)
    }
}

答案 1 :(得分:2)

为了存储方法,您应该记住在类实例上调用该方法。实际存储在数组中的是一个curried函数:

(Test) -> (Int) -> Void

第一个函数接受一个类实例并返回另一个函数,即实际的(Int) -> Void方法,然后在该实例上调用该方法。

为了使其更明确,数组类型为:

var funcArr: [(Test) -> (Int) -> Void] = [Test.func1]

然后你可以用这样的代码调用方法:

var test = Test()
var method = test.funcArr[0]
method(test)(1)

建议阅读:Curried Functions