分段错误 - [NSFileManager defaultManager]上的performSelectorOnMainThread

时间:2014-05-16 13:13:11

标签: objective-c thread-safety segmentation-fault nszombie

此代码似乎不时导致分段错误:

[[NSFileManager defaultManager] performSelectorOnMainThread:@selector(removeItemAtPath:error:) withObject:filePath waitUntilDone:YES];

我想对主线程中的文件执行所有操作,以避免在整个文件夹被迭代时删除文件等冲突。

它产生了这个错误:

Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0x1084

Application Specific Information:
objc_msgSend() selector name: release

这是崩溃主线程的堆栈跟踪:

Thread 0 Crashed:
0   libobjc.A.dylib                      0x39fc8636 objc_msgSend + 22
1   Foundation                           0x30214c67 __NSThreadPerformPerform + 452
2   CoreFoundation                       0x2f7f6fef __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
3   CoreFoundation                       0x2f7f64b7 __CFRunLoopDoSources0 + 204
4   CoreFoundation                       0x2f7f4ca7 __CFRunLoopRun + 628
5   CoreFoundation                       0x2f75f769 CFRunLoopRunSpecific + 522
6   CoreFoundation                       0x2f75f54b CFRunLoopRunInMode + 104
7   GraphicsServices                     0x346bc6d3 GSEventRunModal + 136
8   UIKit                                0x320be891 UIApplicationMain + 1134
9   Pocket3                              0x00050243 main (main.m:4)
10  libdyld.dylib                        0x3a4bcab7 start + 0

我做错了什么?

看起来NSFileManager过早地被释放了,但如果它是单身,怎么会这样呢? 它是否与方法[NSFileManager defaultManager]有关,据说这不是线程安全的?

1 个答案:

答案 0 :(得分:1)

更新:新答案

NSFileManager是线程安全的(只要你没有使用它的委托,你不使用它,你不应该使用-defaultManager)。您可以在当前所在的任何线程上调用[[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]。仅在主线程上执行它没有任何优势。实际上,如果在后台线程中更新文件系统,性能可能会更好,因为如果操作的时间超过预期,UI将不会阻塞。

旧答案(崩溃确实发生的原因)......

方法-removeItemAtPath:error:需要两个对象,但您只提供一个。因此-removeItemAtPath:error:方法将看到的第二个参数(NSError **)只是内存中filePath指针旁边的一些垃圾。

没有-performSelectorOnMainThread:...的版本需要两个对象。您可以改为使用dispatch_sync

dispatch_sync(dispatch_get_main_queue(), ^() {
    NSError *error = nil;
    BOOL ok = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
    if(!ok) {
         NSLog(@"an error happened: %@", error);
    }
}