1

我阅读了一些 UI 界面仅在 MainThread 上更新的信息。

我需要异步更新一些UIButtons,所以我使用performSelectorInBackground它在模拟器和设备(iPad4)上工作正常。

[self performSelectorInBackground:@selector(toggleToUpperWhenSingleShift) withObject:nil];

- (void)toggleToUpperWhenSingleShift{
    shiftStateIndicator = 1;
    for (UIView *aPad in self.subviews) {
        if ( [aPad isKindOfClass:[UIButton class]] ) {
            UIButton *aButPad = (UIButton *)aPad;
            NSMutableString *currentTitle = [NSMutableString stringWithString:[aButPad titleForState:UIControlStateNormal]];
            NSString *firstChar = [currentTitle substringToIndex:1];
            [currentTitle replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar uppercaseString]];
            [aButPad setTitle:currentTitle forState:UIControlStateNormal];
            [aButPad setTitle:currentTitle forState:UIControlStateHighlighted];

            currentTitle = [NSMutableString stringWithString:[aButPad titleForState:UIControlStateSelected]];
            firstChar = [currentTitle substringToIndex:1];
            [currentTitle replaceCharactersInRange:NSMakeRange(0, 1) withString:[firstChar uppercaseString]];
            [aButPad setTitle:currentTitle forState:UIControlStateSelected];
        }
    }
}

我担心如果我保留我的代码会发生一些不需要的功能。谁能给我详细解释一下performSelectorInBackground

为什么不使用它来更新 UI 以及为什么我的应用程序没问题?无论如何调试问题将不胜感激!

4

3 回答 3

7

performSelectorInBackground:几乎从来都不是你想要的,对于几乎任何事情(当然不是自 GCD 创建以来)。它会创建一个您几乎无法控制的新线程。只要您分派给它的方法,该线程就会运行。

通过“小控制”,我的意思是您不会NSThread返回对象,因此很容易多次意外调用此方法并派生无限数量的线程。我已经在几个程序中看到了这种情况。

在 iOS 中,您几乎不应该手动创建线程。GCD 并NSOperation处理几乎所有手动线程可以做的事情,但更好。您通常需要线程池,这样您就不会一直启动和停止线程。GCD 为您提供。您想限制创建的线程数,以免使处理器不堪重负。GCD 为您提供。您希望能够轻松确定后台操作的优先级。GCD 也为您提供。

说了这么多,我不明白你为什么要在后台线程上执行上述操作。几乎所有的工作都是 UI 更新。永远不要尝试在后台线程上修改 UI。这是未定义的行为,当它出错时,它会出错。它在少数情况下起作用的事实毫无意义。UIKit 不是线程安全的。你应该只调用toggleToUpperWhenSingleShift主线程。我看不出有什么东西会阻止你,而且上下文切换到后台线程的开销在这里真的不值得(即使它是安全的,但事实并非如此)。

于 2013-04-04T01:21:01.073 回答
3

Apple 强烈建议不要在后台线程中更改 UI。

您应该使用performSelectorOnMainThread或向 UI 线程的调度队列发送消息,并从那里进行 UI 修改。

dispatch_async(dispatch_get_main_queue(), ^{
  // your code here
});
于 2013-04-01T09:34:11.037 回答
0

强烈建议不要从后台线程(例如计时器、通讯等)更新 UI 控件等。这可能是导致有时很难识别的崩溃的原因。而是使用这些来强制代码在 UI 线程(始终是“主”线程)上执行。

转到http://www.ios-developer.net/iphone-ipad-programmer/development/threads/updating-ui-controls-on-background-threads

供进一步阅读。

于 2013-04-01T10:51:45.100 回答