请考虑以下代码:
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)
的方法。任何聪明的解决方法当然也是受欢迎的。
答案 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