我有一个将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秒钟一次添加一个这样的视图。但是,在整个循环完成之前,父视图上不会显示任何内容。有什么想法吗?
答案 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
。