2011-08-14 217 views
110

我在我的iOS设备中有一个小的sqlitedb。当用户按下按钮时,我从sqlite &中获取数据将其显示给用户。iOS开始后台线程

这个抓取部分我想在后台线程中做(不阻塞UI主线程)。我这样做,像这样 -

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

的获取&后处理的一点点,我需要更新UI。但是,由于(作为一种好的做法),我们不应该从后台线程执行UI更新。我在mainthread叫selector像这样 -

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

但我的应用程序中的第一步崩溃。即开始后台线程。这不是在iOS中启动后台线程的方法吗?

更新1:[self performSelectorInBackground....后,我得到这个堆栈跟踪,没有任何信息含量都没有 -

enter image description here

更新2:我甚至尝试,启动一个后台线程像这样 - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];但仍然我得到相同的堆栈跟踪。

只是让我澄清一下,当我在主线程都执行此操作运行流畅...

更新3这是我想从后台

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids 
{ 
    SpotMain *mirror = [[SpotMain alloc] init]; 
    NSMutableArray *filteredDocids = toProceessDocids; 

    if(![gMediaBucket isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1]; 
    if(![gMediaType isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1]; 
    if(![gPlatform isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1]; 

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids]; 
    [filteredDocids release]; 
    [mirror release]; 

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO]; 
    return; 
} 
+0

什么错误/崩溃日志,你得到什么? – jtbandes

+0

请参阅我的更新... –

+0

您能否在背景中显示您所调用的方法?并确保对象'docids'保留。 – Rog

回答

264

如果使用performSelectorInBackground:withObject:产卵一个新的线程,然后进行选择是负责建立新线程的自动释放池,跑环和其他配置细节 - 见"Using NSObject to Spawn a Thread"苹果线程编程指南英寸

你可能会更好使用Grand Central Dispatch,虽然:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    [self getResultSetFromDB:docids]; 
}); 

GCD是一个较新的技术,并在开销内存方面和代码行更有效。


更新带帽子尖端Chris Nolet,谁建议的改变,使得上面的代码更简单,苹果最新的GCD代码示例保持向上。

+0

酷!不知道这个。这是否适用于'[NSThread detachNewThreadSelector:@selector ....'也? –

+0

是的。根据Apple文档,调用'performSelectorInBackground:withObject:'“与将当前对象,选择器和参数对象作为参数调用'detachNewThreadSelector:toTarget:withObject:'NSThread方法'相同。 –

+0

在这件事情中,'(unsigned long)NULL'和'0'之间有区别吗? – Sti

4

运行的方法启用NSZombieEnabled以了解哪个对象正在释放并被访问。 然后检查getResultSetFromDB:是否与此有关。同时检查docids里面是否有内容,以及是否保留。

这样你就可以肯定没有什么不对。

+0

请复制您在主线程上使用的流畅运行的行。 –

+0

我使用这个从主线程&至少它击中该方法,而不是突然崩溃 - '[self getResultSetFromDB:docids];' –

+0

你有没有启用我告诉你? –

2

iOS自带的默认sqlite库不是使用SQLITE_THREADSAFE宏编译的。这可能是你的代码崩溃的原因。

2

斯威夫特2.x的答案:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     self.getResultSetFromDB(docids) 
    } 
4

嗯,这是相当有GCD其实很容易。典型的工作流程是这样的:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul); 
    dispatch_async(queue, ^{ 
     // Perform async operation 
     // Call your method/function here 
     // Example: 
     // NSString *result = [anObject calculateSomething]; 
       dispatch_sync(dispatch_get_main_queue(), ^{ 
        // Update UI 
        // Example: 
        // self.myLabel.text = result; 
       }); 
    }); 

更多关于GCD你可以看看到Apple's documentation here