【问题标题】:iOS start Background ThreadiOS启动后台线程
【发布时间】:2011-10-26 16:37:50
【问题描述】:

我的 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.... 之后,我得到了这个堆栈跟踪,没有任何信息 -

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

澄清一下,当我在主线程上执行此操作时,一切运行顺利...

UPDATE 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;
}

【问题讨论】:

  • 你得到什么错误/崩溃日志?
  • 请看我的更新...
  • 能否请您在后台显示您正在调用的方法?并确保对象docids 被保留。
  • 是的,docidsretain。我把它放在.h 中作为@property (nonatomic, retain) NSMutableArray *docids;
  • 不要在方法前面加上get;那应该只是resultSetFromDB:

标签: objective-c ios multithreading uikit core-foundation


【解决方案1】:

如果您使用performSelectorInBackground:withObject: 生成一个新线程,那么执行的选择器负责设置新线程的自动释放池、运行循环和其他配置细节——请参阅 Apple 的 线程编程指南中的"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 致敬,Chris Nolet 建议进行更改以简化上述代码并跟上 Apple 最新的 GCD 代码示例。

【讨论】:

  • 酷!不知道这个。这是否也适用于[NSThread detachNewThreadSelector:@selector....
  • 是的。根据 Apple 文档,调用 performSelectorInBackground:withObject:“与使用当前对象、选择器和参数对象作为参数调用 NSThreaddetachNewThreadSelector:toTarget:withObject: 方法相同。”
  • 这件事上(unsigned long)NULL0有区别吗?
  • @Sti from apple Dev Docs:注意:dispatch_get_global_queue 函数的第二个参数是为将来扩展保留的。目前,您应该始终为此参数传递 0。
  • 我应该使用 performSelectorOnMainThread 用操作结果更新 UI 还是有更一致的方法用 GCD 更新 UI?
【解决方案2】:

嗯,实际上使用 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

【讨论】:

    【解决方案3】:

    Swift 2.x 答案:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        启用NSZombieEnabled 以了解正在释放然后访问哪个对象。 然后检查getResultSetFromDB: 是否与此有关。还要检查docids 里面是否有任何东西,是否被保留。

        这样你就可以确定没有问题。

        【讨论】:

        • 请复制您使用的在主线程上运行流畅的行。
        • 我在主线程中使用它并且至少它会命中该方法而不是突然崩溃 - [self getResultSetFromDB:docids];
        • 我告诉你的你启用了吗?
        • 在这一行放一个断点:SpotMain *mirror = [[SpotMain alloc] init]; 并告诉我它是否命中,如果是tehn,哪一行崩溃。请启用僵尸,以便我们获得清晰的错误日志。
        • 是的,我启用了僵尸。我明白了 - ` 2011-08-14 12:49:42.697 FLO[16211:707] *** -[FMResultSet release]: message sent to deallocated instance 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...`,进入后台线程后很快崩溃...
        猜你喜欢
        • 1970-01-01
        • 2013-02-16
        • 2023-01-30
        • 1970-01-01
        • 1970-01-01
        • 2020-10-15
        • 1970-01-01
        • 1970-01-01
        • 2023-03-30
        相关资源
        最近更新 更多