【问题标题】:What's happen if control UI by performSelectorInBackground?如果通过 performSelectorInBackground 控制 UI 会发生什么?
【发布时间】:2013-04-01 09:07:13
【问题描述】:

我读到了一些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 以及为什么我的应用可以使用它? 无论如何调试问题将不胜感激!

【问题讨论】:

  • 我需要异步更新一些 UIButtons 是什么意思?在 UIView 文档链接下方(阅读 Threading Considerationsdeveloper.apple.com/library/ios/#documentation/UIKit/Reference/…
  • performSelectorInBackground 与普通方法是异步的。我理解错了吗?
  • 阅读以下讨论stackoverflow.com/questions/11122957/…performSelectorInBackground 这是一种同步方法。这意味着其中的代码将以串行方式执行。但在不同的线程中。例如,异步模式是 async NSURLConnection 使用的模式。
  • 谢谢!我误解了不同的线程是异步的。

标签: ios objective-c multithreading user-interface uiview


【解决方案1】:

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

我所说的“小控制”是指您没有得到NSThread 对象,因此很容易不小心多次调用此方法并派生无限数量的线程。我已经在几个程序中看到过这种情况。

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

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

【讨论】:

    【解决方案2】:

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

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

    dispatch_async(dispatch_get_main_queue(), ^{
      // your code here
    });
    

    【讨论】:

      【解决方案3】:

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

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

      供进一步阅读。

      【讨论】:

      • 请注意,定时器通常不在后台线程上运行。 NSTimer 特别是通常在主线程上运行,并且适用于 UI 更新。我不知道您所说的“通讯”是什么意思,但请注意 NSURLConnection 回调通常也在主线程上。但是你是正确的,你永远不应该在背景线程上更新 UI 控件。
      猜你喜欢
      • 2011-09-19
      • 1970-01-01
      • 2021-05-17
      • 2018-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-25
      相关资源
      最近更新 更多