转载

代码的坏味道之performBlockAndWait的逆袭

自从iOS5之后苹果给NSManagedObjectContext添加了performBlockAndWait和performBlock(swift中是performAndWait和perform),CoreData的线程安全问题处理就变得简单了许多,但是作为一个有一点经验的程序员都会隐隐的感觉到performBlockAndWait这个函数看起来并可靠,等待block结束,那我如果递归调用这个函数呢,老司机肯定想到了这个问题——死锁。所以我就做了一个小实验:

managedObjectContext.performAndWait {
    self.managedObjectContext.performAndWait {
        NSLog("如果没有死锁,就打印我把!!!")
    }
}

很简单,如果不会死锁那就应该打印出来,当然结果是能够打印,看到这里,就会发现这个函数还是比较神奇的,所以我去查阅了一下苹果的官方文档,是这样写的:

Synchronously performs a given block on the receiver’s queue.

You use this method to send messages to managed objects if the context was initialized using NSPrivateQueueConcurrencyType or NSMainQueueConcurrencyType.

This method may safely be called reentrantly.

注意最后一句,苹果申明了这个函数是可以安全的递归调用的,不得不佩服苹果的API设计能力之强大。

很显然performBlockAndWait这个函数不像我们表面上看的那样在一个线程里执行,那苹果是通过什么机制保证这个函数在被递归调用时的安全性的呢,我们看不到苹果的源码,所以只能做大致的猜测:

//模拟实现performBlockAndWait
func performBlockAndWaitMock(_ block: @escaping () -> Swift.Void) {
    let semaphore = DispatchSemaphore(value: 0)
    operationQueue.addOperation {
        block()
        semaphore.signal()
    }
    semaphore.wait()
}

大概是这样的函数,所以如果我们要设计一个借口,实现类似的将一段逻辑抛掷到同步函数函数中去执行,就一定要考虑函数的递归安全的特性,否则这个函数就是有隐患的,最后附上Demo

正文到此结束
Loading...