添加到子视图的项目不会逐步显示

时间:2014-03-31 16:04:16

标签: ios objective-c xcode cocoa

我有一个将UIView元素添加到另一个父UIView的线程。我试图每秒添加一个,但是在整个循环完成之前它们不会显示。请参阅下面的代码。

-(void)buttonClicked:(id)sender {
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addSubViews) object:nil];
    [thread start];
}

-(void)addSubViews {
    for(int i = 0; i < 10; i++) {
        UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i, 0, 10, 10)];
        [parentView addSubview:view];
        [NSThread sleepForTimeInterval:1];
    }
}

我希望每1秒钟一次添加一个这样的视图。但是,在整个循环完成之前,父视图上不会显示任何内容。有什么想法吗?

3 个答案:

答案 0 :(得分:0)

UIKit不是线程安全的,因此所有对它的调用都必须在主线程上进行。试试这个:

-(void)addSubViews {
    for(int i = 0; i < 10; i++) {
        dispatch_sync( dispatch_get_main_queue(), ^{
            UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i, 0, 10, 10)];
            [parentView addSubview:view];
        } );
        [NSThread sleepForTimeInterval:1];
    }
}

答案 1 :(得分:0)

请勿使用NSThread,请使用GCD。例如:

-(void)buttonClicked:(id)sender {
    [self addSubViews];
}

-(void)addSubViews {

  for (int i = 0; i < 10; i++) {

    dispatch_async(dispatch_get_main_queue(), ^{
      UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i, 0, 10, 10)];
      [parentView addSubview:view];
      [NSThread sleepForTimeInterval:1.0];
    });

  }
}

说明:您添加了10个异步任务来添加子视图并等待1秒到主队列。

答案 2 :(得分:0)

GACK。忘记你曾经知道睡眠。真。

您无法从后台线程执行UI代码。

在下一次通过事件循环之前,对应用程序UI的更改不会生效。您需要返回并让系统处理您的代码。更像是这样:

标题:

@interface MyVC: UIViewController
{
  int viewIndex;
}

身体:

#define K_MAX_VIEWS 10

@implementation MyVC

-(void)buttonClicked:(id)sender 
{
  viewIndex = 0;
  [self addViews];
}

- (void) addViews;
{
  if (viewIndex < K_MAX_VIEWS)
  {
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i*15, 0, 10, 10)];
    [parentView addSubview:view];
    view.layer.borderWidth = 1.0 //Testing: Box the view so you can see it.
    viewIndex++;
    [self performSelector: @selector(addViews) withObject: nil afterDelay: 1];
  }
}
@end


此代码使用实例变量来跟踪其添加的视图的索引。在调用performSelector:withObject:afterDelay:后,它会添加一个视图,然后返回。此方法在延迟后调度主线程上的将来调用。这就是你想要处理的方式。

请注意,除非您在视图中添加显示内容,否则您可能不会在此代码中看到任何内容。这就是为什么我添加了行view.layer.borderWidth = 1.0