【问题标题】:Is it ok to create a UIView on a background thread?可以在后台线程上创建 UIView 吗?
【发布时间】:2012-06-22 18:58:09
【问题描述】:

我知道 UIView 不是线程安全的,所以我不能在后台线程上添加视图,要解决这个问题,是否可以在后台线程上创建 UIView 然后将其添加到主线程上?

注意:我不在主线程上执行此操作的原因是因为我的实际代码要复杂得多,因此需要一段时间来创建所有视图并填充值。我不希望 UI 在执行此操作时变得无响应,因此我正在尝试解决此问题。

例如..

-(void)addLabel//called on background thread
{
    UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0,0,40,100)];
    [label setText:@"example"]
    [self.view performSelector:@selector(addSubview:) onThread:[NSThread mainThread] withObject:example waitUntilDone:YES];
}

提前致谢。

【问题讨论】:

  • 我相信你说的没错。在后台创建它,但在主界面上更新 UI。

标签: objective-c ios uiview uiviewcontroller nsthread


【解决方案1】:

来自UIView

线程注意事项

对应用程序用户界面的操作必须在主线程上进行。因此,您应该始终从应用程序主线程中运行的代码调用 UIView 类的方法。唯一可能不是绝对必要的情况是在创建视图对象本身时,但所有其他操作都应在主线程上进行。

initWithFrame: 的调用显然不是线程安全的。对setText: 的调用可能不是线程安全的,属于“操作”条款。这些当然不承诺是线程安全的。

努力找出后台线程上的数据。然后在主线程上创建您的视图。如果有大量视图,您可以尝试使用多个 dispatch_async() 调用将工作拆分到主队列中。这可能会让 UI 保持响应;我还没有对它进行过广泛的实验。

您可能还想考虑在可能的情况下从UIView 切换到CALayer。大多数CALayer 工作可以在后台线程上完成。如果您有大量的视图,那可能无论如何都是低效的。如果只是计算视图数据需要很长时间,则表明您没有正确分离模型和视图信息。模型类应该独立于创建视图来计算所需的一切。

【讨论】:

  • 很抱歉,您能澄清一下您的答案吗?苹果的引述特别说在后台创建一个视图是可以的,但你说它不是。为什么?
  • @iamataptool 也许您可以使用init 方法安全地创建UIView,但不能使用initWithFrame: 方法?
  • CALayer 小贴士成就了我的每一天和一周。非常感谢!
  • 我不同意模型类应该计算在视图中显示所需的所有内容。模型类应该将它们的逻辑限制在概念上与其目的相关的范围内。如果您需要逻辑来更改或转换模型信息以进行显示,则应由控制器或中间视图模型完成。
【解决方案2】:

我使用 Xcode 9.0 beta 3 (9M174d),收到警告。

[UView init] 只能从主线程调用

所以我认为你应该更好地在主线程中创建 UI

显示下图:

【讨论】:

    【解决方案3】:

    Drawing and Printing Guide 声明:

    重要 UIKit 类通常不是线程安全的。所有与绘图相关的操作都应在应用程序的主线程上执行。

    因此,据我了解,似乎唯一的问题与“绘图相关操作”有关。如果我们假设正确的类只在其drawRect: 方法中执行此类操作,那么您建议的方法应该没问题。

    【讨论】:

    • 在我的例子中,我的应用是通过UIApplicationLaunchOptionsLocalNotificationKey 唤醒的,所以它在后台。可以吗,如果我在应用程序处于后台时执行子视图添加? stackoverflow.com/questions/46584566/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    相关资源
    最近更新 更多