swift值类型的线程安全

3,866 阅读1分钟

swift中的值类型

swift中不同于oc,数组和字典等都被定义为了值类型,而与之对应的类属于引用类型。当然值类型还包括结构体和枚举。值类型有一个优点就是线程安全,本篇也只讨论其线程安全的问题。

一个有趣的例子

有这样一段代码,判断下输出结果以及会不会crash:

let queue = DispatchQueue.global()

var animals = ["dog", "cat", "pig"]

queue.async {
    let count = animals.count
    for index in 0 ..< count {
        print("\(animals[index])")
        Thread.sleep(forTimeInterval: 1)
    }
}

queue.async {
    Thread.sleep(forTimeInterval: 0.5)
    animals.remove(at: 0)
}

运行结果会打印出来dogpig然后crash掉了,报错信息:

Thread 4: Fatal error: Index out of range。

原因就是我们在读取数组第二个元素时,第一个元素被移除掉了,所以会打印出来pig。然后当读取第三个元素时,数组內已无第三个元素,所以就会越界crash。那么是不是就意味着值类型并不是线程安全的呢?

真实的线程安全

通过上面的例子不难看出值类型的数组在这种多线程读写的情况下并不是线程安全的。我们所说的线程安全是这样的:

queue.async { [animals] in
    let count = animals.count
    for index in 0 ..< count {
        print("\(animals[index])")
        Thread.sleep(forTimeInterval: 1)
    }
}

通过对这段代码的修改我们就可以得到想要的结果,并且不会crash。因为此时在新的线程中会copy出一份新的animals。所以当线程会copy值类型内容时是线程安全的,其他情况会存在线程不安全的隐患,我们使用时应当注意。