加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

在闭包中使用数组时Swift EXC_BAD_ACCESS

发布时间:2020-12-14 04:41:54 所属栏目:百科 来源:网络整理
导读:考虑以下玩具示例 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 a
考虑以下玩具示例 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({ (myArr : [AnyObject]) -> () in
    for e in myArr{
      self.arr.append(e as MyObj)
    }
    self.didRun = true
 })

但我更感兴趣的是为什么我的第一个代码不起作用.

如果有人可以向我解释Swift中的闭包语义以及为什么上面会产生这样的错误,我将不胜感激.

解决方法

编辑:正如 @SevenTenEleven(苹果员工) ADF thread related to this question所述:

It looks like there are issues with some covariant array assignments; please file a bug so we can either properly ban them at compile-time or properly implement them at runtime.

我们这样做,I did.

做了一些experiments和research后,我得出以下结论:

>这与clousures和外部范围无关
>只有将[AnyObject]向下转换为[MyObj]时才会发生错误
>只有将“外部”变量声明为协议类型数组时,错误才会出现

由于似乎提供者总是返回Testable,因此我能够通过更改提供者函数声明并将变量显式标记为Testable数组来使代码工作:

func provider(cb: [Testable] -> ()) {
    let a : [Testable] = [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()]
        cb(a)
    }
}

let t = Test()
t.run()
t.run()

前面的代码输出:

arr has 3 elements
_TtC5hgfds5MyObj
_TtC5hgfds5MyObj
_TtC5hgfds5MyObj

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读