在Objective-C中执行performselectoronmainthread的最佳方式是什么?

7
我正在编写一款 iPhone 的客户端服务器应用程序。我有一个关于线程的问题。当我从设备访问在线数据库时,我需要在单独的线程上执行此操作,以避免冻结 UI / 主线程。但是,当响应从数据库获取的数据时,我会在主线程上调用此方法:performSelectorOnMainThread。问题是这只能让我向方法发送一个参数/对象(WithObject),有时我有更多要传递的参数。另一件事是我必须传递这个对象,如果我传递 nil,应用程序会崩溃。
这是我的代码,我担心我使用方法和线程的方式不对。
- (IBAction)testServerAction:(id)sender {

    [self.imageView setHidden:YES];
    [self.activityView setHidden:NO];
    [self.activityView startAnimating];
    dispatch_queue_t testServer = dispatch_queue_create("Test-Server-Thread", NULL);
    dispatch_async(testServer, ^{

        if ([self.arrayWithServerConnections count] > 0)
        {
            NSString *messageToShow;
            if ([self testServerMethod])
            {
                messageToShow = @"Server is working!";
                [self performSelectorOnMainThread:@selector(showMessageBoxWithString:) withObject:messageToShow waitUntilDone:YES];
                [self performSelectorOnMainThread:@selector(threadedUIActivityRemover:) withObject:nil waitUntilDone:YES];
            }else
            {
                messageToShow = @"Server is NOT working!";
                [self performSelectorOnMainThread:@selector(showMessageBoxWithString:) withObject:messageToShow waitUntilDone:YES];
                [self performSelectorOnMainThread:@selector(threadedUIActivityRemover:) withObject:nil waitUntilDone:YES];
            }
        }

    });

    dispatch_release(testServer);
}

-(void)threadedUIActivityRemover:(NSString *)string
{
    [self.imageView setHidden:NO];
    [self.activityView setHidden:YES];
    [self.activityView stopAnimating];
}

这是一种好的做法吗?除了performSelectorOnMainThread,你还能指出其他更好的方法吗?

正如您所看到的,在此示例中,我向一个NSString参数传递了nil,因为我必须传递一些东西。如果我在该方法中没有NSString作为参数,即使传递nil,应用程序也会崩溃。为什么会这样?请帮我澄清一下!

//谢谢!

4个回答

10

嗯,你已经在使用dispatch_async了。那么你应该只是使用

     dispatch_async(dispatch_get_main_queue(),^ { ... } );

可以从后台线程中调用主线程以执行一些操作。例如,

     if ([self testServerMethod])
        {
            dispatch_async(dispatch_get_main_queue(),^ {
               [self showMessageBoxWithString: @"Server is working!"];
               [self threadedUIActivityRemover:nil];
            } );
        }else ...

调用的方法没有参数数量上的限制。


这个方法非常有效,完全符合我的要求。PerformSelectorOnMainThread对我来说有点约束!这太棒了!我在这种方式下切换线程时应该注意什么?是否有任何情况下我不应该使用异步等? - Objective Coder
你知道吗,在早期我们只有detachNewThreadSelectorperformSelectorOnMainThread。现在我们有了dispatch_*NSOperationQueue。现在一切都变得更加容易了。通常情况下,如果你不需要在后台线程中更新UI,那么async就可以正常工作。 - Yuji
好的,很高兴我不是来自古代 =)。这似乎非常顺畅。非常感谢您的帮助!我会阅读一些文档,更好地了解dispatch_*的工作原理.. 谢谢! - Objective Coder
我在使用dispatch_async(dispatch_get_main_queue()时遇到了问题(从未完全弄清原因),但UI会挂起,但使用performSelectorOnMainThread却可以正常工作。 - gheese

2

传递一个集合,例如未解档对象的字典。


是的,我可以做到。但是,这似乎很奇怪。为什么不能有一个performSelectorOnMainThread而不必传递任何东西呢?还有一件事。我也无法从这个方法中对我的代理执行选择器。我必须在self中调用一个方法。这也意味着我必须为此编写许多方法。这些方法只是为了从这个方法中调用。 - Objective Coder
1
你可以将 nil 作为参数传递给 performSelectorOnMainThread 函数 - 如果应用程序崩溃了,那不是 Foundation.framework 中实现的结果。 - justin

1

你也可以使用 NSInvocation


GIYF - 这是最顶尖的结果之一:http://stackoverflow.com/questions/2963933/performing-selectors-on-main-thread-with-nsinvocation - justin

0

既然您正在传递实例变量,另一个选项是传递self并使self线程安全。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接