使用 GCD 添加 UIView
在我正在开发的应用程序中,我有一个水平 UIScrollView
用作一种表格视图。
向其中添加子视图会阻塞主线程,因此我决定改用 GCD,并在后台线程中创建视图并将它们添加到主队列中的 UIScrollView 实例中。
相关代码是这样的:
NSUInteger numberOfItems = [_dataSource numberOfItemsInBandView:self];
CGFloat __block nextX = 0.0;
dispatch_queue_t bgQueue = dispatch_queue_create("bandview", NULL);
for (NSUInteger i = 0; i < numberOfItems; i++) {
dispatch_async(bgQueue, ^{
UIView *itemView = [_dataSource bandView:self viewForItemAtIndex:i];
itemView.frame = CGRectMake(nextX, 0, itemView.frame.size.width, itemView.frame.size.height);
dispatch_async(dispatch_get_main_queue(), ^{
[_scrollView addSubview:itemView];
_scrollView.contentSize = CGSizeMake(nextX, self.frame.size.height);
});
nextX += itemView.frame.size.width;
});
}
dispatch_release(bgQueue);
_scrollView
是一个UIScrollView
实例(正确初始化)。
我期望看到子视图被一一添加到 UIScrollView
中,但相反,我所经历的是一切都异步运行,然后滚动条刷新并立即添加所有子视图(这不是我所期望的)。
有人能发现我在这里缺少什么吗?
In an application I'm developing, I have a horizontal UIScrollView
that is used as a sort of table view.
Adding the subviews to it blocked the main thread, so I decided to use GCD instead, and create the views in a background thread and add them to the UIScrollView
instance in the main queue.
The relevant code is this:
NSUInteger numberOfItems = [_dataSource numberOfItemsInBandView:self];
CGFloat __block nextX = 0.0;
dispatch_queue_t bgQueue = dispatch_queue_create("bandview", NULL);
for (NSUInteger i = 0; i < numberOfItems; i++) {
dispatch_async(bgQueue, ^{
UIView *itemView = [_dataSource bandView:self viewForItemAtIndex:i];
itemView.frame = CGRectMake(nextX, 0, itemView.frame.size.width, itemView.frame.size.height);
dispatch_async(dispatch_get_main_queue(), ^{
[_scrollView addSubview:itemView];
_scrollView.contentSize = CGSizeMake(nextX, self.frame.size.height);
});
nextX += itemView.frame.size.width;
});
}
dispatch_release(bgQueue);
_scrollView
is a UIScrollView
instance (properly initialized).
What I expected is to see the subviews be added to the UIScrollView
one by one, but instead, what I'm experiencing is that everything runs asynchroniously, and then the scrollbars refreshes with all its subviews added at once (which is not what I expect).
Can anyone spot what I'm missing here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
UI
更改需要在主线程上进行。在后台线程(异步 gcd 队列)中执行 UI 更改将导致您所看到的未定义/不良行为。添加子视图似乎不太可能是问题的主要原因。问题可能在于为子视图检索数据的方式。解决方案是添加所有子视图,然后异步检索它们的数据,然后在操作完成时更新它们。还要考虑不添加用户不可见的视图,并在用户滚动时动态添加它们,类似于 UITableView 的工作方式。UI
changes need to happen on the main thread. PerformingUI
changes in a background thread (async gcd queue) will result in undefined/undesirable behavior as you are seeing. It seems unlikely that adding subviews is the main cause of the problem. The issue likely lies in the way the data is retrieved for the subviews. A solution would be to add all of the subviews then retrieve the data for them asynchronously, and then update them as the operation completes. Also consider not adding views that will not be visible to the user, and add them dynamically as the user scrolls similar to how aUITableView
works.另一件值得指出的事情是,您已经创建了一个串行队列(bandview)来将 UIView 创建请求分派到其中,但这也意味着每个创建请求将以线性顺序发生,而不是以尽可能并发的方式创建。如果这不是所需的行为,您可以尝试将创建请求分派到全局并发队列之一。
Another thing worth pointing out is that you have created a serial queue (bandview) to dispatch the UIView creation requests into, but this also means that each creation request will happen in linear order vs being created in the most concurrent fashion possible. You might try dispatching the creation requests onto one of the global concurrent queues if that's not the desired behavior.