考虑以下玩具示例Swift代码:
protocol Testable{}
class MyObj : Testable{}
class Test {
var arr:[Testable] = []
var didRun:Bool = false
func run() -> [Testable]{
if(didRun){
println("arr has \(arr.count) elements")
for e in arr{ // following access causes EXC_BAD_ACCESS
println(e)
}
return arr
} else{
provider({ (myArr : [AnyObject]) -> () in
self.arr = myArr as [MyObj]
self.didRun = true
})
return []
}
}
func provider( cb : ([AnyObject] -> ()) ){
let a:[MyObj] = [MyObj(),MyObj(),MyObj()]
cb(a)
}
}
并按以下方式调用:
let t = Test()
t.run()
t.run()
这会在尝试迭代返回的数组时编译但在运行时崩溃。 arr.count
也是垃圾,返回一个随机的大数字,例如232521760
,而arr
本身指向远离0xfffffff9
的某个地方,这意味着很明显它的垃圾。
我的问题是这是为什么?编译器不会抱怨类型错误。为什么我无法使用myArr
数组,编译器在离开闭包后是否进行了myArr
解除分配?
我可以通过将provider
调用更改为:
provider({ (myArr : [AnyObject]) -> () in
for e in myArr{
self.arr.append(e as MyObj)
}
self.didRun = true
})
但我更感兴趣的是为什么我的第一个代码不起作用。
如果有人可以向我解释Swift中的闭包语义以及为什么上面会产生这样的错误,我将不胜感激。
答案 0 :(得分:3)
修改:
看起来某些协变阵列分配存在问题;请提交一个错误,以便我们可以在编译时正确禁止它们或在运行时正确实现它们。
我们这样做, I did 。
在做了一些experiments和research之后,我得出了以下结论:
[AnyObject]
投降[MyObj]
由于似乎provider
始终会返回Testable
,因此我可以通过更改provider
函数声明并明确标记a
变量来使代码正常工作数组Testable
:
func provider(cb: [Testable] -> ()) {
let a : [Testable] = [MyObj(), MyObj(), MyObj()]
cb(a)
}
然后没有必要贬低,所以没有错误。这是整个代码:
protocol Testable {}
class MyObj : Testable {}
class Test {
var arr : [Testable] = []
var didRun = false
func run() -> [Testable] {
if didRun {
println("arr has \(arr.count) elements")
for e in arr {
println(e)
}
return arr
} else {
provider() { (myArr : [Testable]) in
self.arr = myArr
self.didRun = true
}
return []
}
}
func provider(cb: [Testable] -> ()) {
let a : [Testable] = [MyObj(), MyObj(), MyObj()]
cb(a)
}
}
let t = Test()
t.run()
t.run()
前面的代码输出:
arr has 3 elements
_TtC5hgfds5MyObj
_TtC5hgfds5MyObj
_TtC5hgfds5MyObj
答案 1 :(得分:3)
似乎swift不喜欢AnyObject或协议数组上的for-in循环。但是,如果你把它改成一个老式的for-i循环,事情就可以了。
所以而不是:
for e in arr { // causes EXC_BAD_ACCESS
只需写下:
for var i = 0; i < arr.count; ++i { // works fine
let e = arr[i]
...
}