iOS启动后台线程


117

我的iOS设备中有一个小sqlitedb。当用户按下按钮时,我从sqlite获取数据并将其显示给用户。

我要在后台线程中执行此操作(不阻塞UI主线程)。我这样做-

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

经过提取和一些处理后,我需要更新UI。但是由于(作为一种好习惯),我们不应该从后台线程执行UI更新。我selector这样在主线程上调用-

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

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

更新1:[self performSelectorInBackground....获得此stacktrace之后,再也没有任何信息-

在此处输入图片说明

更新2:我什至尝试启动这样的后台线程- [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];但仍然得到相同的stacktrace。

就像我澄清的那样,当我在主线程上执行此操作时,一切运行顺利...

更新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;
}

您得到什么错误/崩溃日志?
jtbandes

请查看我的更新...
Srikar Appalaraju 2011年

您能否在后台显示您要调用的方法?并确保docids保留该对象。
罗格

是的,docidsretain。我已将其输入.h@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju 2011年

不要在方法前加上get; 那应该只是resultSetFromDB:
bbum

Answers:


270

如果performSelectorInBackground:withObject:用于生成新线程,则执行的选择器负责设置新线程的自动释放池,运行循环和其他配置详细信息-请参阅 Apple 线程编程指南中的“使用NSObject生成线程”

不过,使用Grand Central Dispatch可能会更好:

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

GCD是一种较新的技术,在内存开销和代码行方面更为高效。


克里斯·诺莱特Chris Nolet)用帽子技巧进行了更新,他提出了一项更改,使上面的代码更简单,并且与Apple最新的GCD代码示例保持一致。


凉!不知道这个 这[NSThread detachNewThreadSelector:@selector....也适用吗?
Srikar Appalaraju 2011年

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

(unsigned long)NULL0在这件事上有区别吗?
2014年

4
apple Dev Docs中的 @Sti :注意:dispatch_get_global_queue函数的第二个参数保留给以后使用。现在,您应该始终为该参数传递0。
Jawad Al Shaikh,2014年

然后,我应该使用performSelectorOnMainThread来用操作结果更新UI还是使用GCD更新UI的更一致方法?
伊利亚·丹尼索夫

9

嗯,使用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的文档。


4

使NSZombieEnabled能够知道要释放哪个对象然后再访问它。然后检查getResultSetFromDB:与这是否有关。还要检查docids内部是否有东西,是否保留。

这样,您可以确定没有错。


请复制您在主线程上顺利运行的行。
Nicolas S

我在主线程中使用它,并且至少使用了该方法,而不是突然崩溃[self getResultSetFromDB:docids];
Srikar Appalaraju 2011年

你启用了我告诉你的吗?
Nicolas S

在此行中添加一个断点: SpotMain * mirror = [[SpotMain alloc] init]; 并告诉我它是否命中,如果撞到,哪一行崩溃。请启用僵尸,以便我们获得清晰的错误日志。
Nicolas S

是的,我启用了僵尸。我明白了-`2011-08-14 12:49:42.697 FLO [16211:707] ***-[FMResultSet版本]:消息发送到已释放实例0x2bff80 2011-08-14 12:49:42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool():类__NSCFData的对象0x2c0cc0自动释放,没有池-只是泄漏. Also when I try to call this method from background thread I do not reach SpotMain * mirror ...`,它在进入后台线程后很快崩溃...
Srikar Appalaraju,2011年

2

iOS随附的默认sqlite库未使用SQLITE_THREADSAFE宏进行编译。这可能是代码崩溃的原因。


2

Swift 2.x答案:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.