比-forwardInvocation更快的方式:在特定线程上执行消息

时间:2011-06-18 01:03:01

标签: iphone objective-c multithreading cocoa-touch sqlite

为了提高响应能力,一些使用FMDB在主线程上执行SQLite查询的同步方法被重写为异步,并通过-performSelectorInBackground:withObject:在后​​台运行。但是,SQLite不是线程安全的,这些方法中的每一个最终都会调用-[FMDatabase open],从而降低整体性能。

因此,我为FMDB类编写了一个代理,它通过-forwardInvocation:覆盖-[NSInvocation invokeWithTarget:]以在一个特定线程上执行-performSelector:onThread:withObject:waitUntilDone:。这解决了对-[FMDatabase open]的调用过多的问题,但-forwardInvocation:本身相当昂贵。

有没有一种很好的方法可以解决这个性能问题而无需重写所有调用FMDB方法的代码?

1 个答案:

答案 0 :(得分:2)

您已发现问题:请勿拨打-performSelectorInBackground:withObject:!我们无法保证它会做什么,但它可能不会做正确的事情。

如果您想要的是单个"数据库线程"对于后台操作,那么有几个选项:

  • 创建一个新的数据库线程并运行循环并改为使用-performSelector:onThread:...
  • 使用maxConcurrentOperationCount = 1创建一个NSOperationQueue并使用NSOperation(可能是NSInvocationOperation?)或串行调度队列。 这不是很正确:操作/块不能保证在同一个线程上执行,这可能会破坏sqlite(IIRC你只能在释放所有语句后在线程之间移动数据库句柄)
  • 使用NSOperationQueue,但在[[NSThread currentThread] threadDictionary]中保存对数据库的线程本地引用。这有点乱,因为您几乎无法控制数据库何时消失。它也可能违反NSOperation合同(当操作完成时,你应该将线程恢复到原始状态。)