前言
前段时间看app的线上奔溃总是出现意义不明的崩溃问题,而且崩溃栈出现在闭包的回调里,并且bugly上提示说是有可能在swift解包的时候出现问题,也就是对nil使用了!。这就完全误导了我,把我对问题的理解定义为数据保护的不够到位。结果就是在多次发版后这个问题还未得到解决,所以我绝对对这个问题一探究竟。
出现问题的原因
其实出现这个问题的原因很简单,那就是group的enter和leave没有成对出现。比如说我们会在闭包的回调里去leave,但是闭包有可能返回多次,一旦多leave了,那么就会出现EXC_BAD_INSTRUCTION这个问题。
举个例子
我们声明如下两个方法,可以看出来work2回调了两次
func work1(closure: () -> Void) {
sleep(1)
closure()
}
func work2(closure: () -> Void) {
closure()
sleep(2)
closure()
}
接着我们使用它们
override func viewDidLoad() {
super.viewDidLoad()
let group = DispatchGroup()
let queue = DispatchQueue(label: "test", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
group.enter()
queue.async {
self.work1 {
group.leave()
}
}
group.enter()
queue.async {
self.work2 {
group.leave()
}
}
group.notify(queue: queue) {
print("同步完成")
}
}
这里可以看出来在work2的闭包的leave就会出现这个问题。
解决方法
其实这种问题完全使我们编写代码的过程中不够细心导致的,通过完善的测试用例完全可以避免问题发生,但是我们还是需要记住一句话DispatchGroup的enter和leave必须成对出现!!!