UISegmentedControl有两个UICollectionViews来显示图像。 MULTITHREADING

时间:2014-10-27 22:15:38

标签: ios objective-c multithreading uicollectionview uisegmentedcontrol

所以我的目标是创造这样的东西:

enter image description here

enter image description here

我的问题是当我在段之间切换时,我想显示一个UIActivityViewIndicator旋转,因为它需要一些时间来加载图像(本地存储所以理论上这应该快得多......)。但是在切换到新单元格的图像之前,线程似乎又回来了。

我做错了什么?

这是我的代码:

- (void)reloadCollection {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    [_myCollection reloadData];
    [_myCollection layoutIfNeeded];

    dispatch_async(dispatch_get_main_queue(), ^{

        _spinnerView.hidden = YES;

    });
});

}

- (IBAction)segmentedControlSwitched:(id)sender{

_spinnerView.hidden = NO;

[self reloadCollection];

}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;

}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {


if ([_mySegmentedControl selectedSegmentIndex] == 0){
    return [_photosTaken count];
}else
    return [_photosTagged count];

}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell;
UIImageView *imageView;

if ([_mySegmentedControl selectedSegmentIndex] == 0){
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
imageView = [[UIImageView alloc] initWithImage:[_photosTaken objectAtIndex:indexPath.row]];

}
else
{
cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell1" forIndexPath:indexPath];
imageView = [[UIImageView alloc] initWithImage:[_photosTagged objectAtIndex:indexPath.row]];

}

imageView.frame = cell.frame;
[cell setBackgroundView:imageView];
return cell;

}

谢谢, JoãoGarcia。

4 个答案:

答案 0 :(得分:2)

dispatch_get_global_queue获取并发调度队列,其中多个任务并行运行。它是后台队列,应该在mainQueue上执行UI更新,因此[_myCollection layoutIfNeeded]应该移动到dispatch_async(dispatch_get_main_queue(), 在并发后台队列上更新UI会导致奇怪的行为,例如暂停或冻结。

你可以尝试一下。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    // do time consuming things here

    dispatch_sync(dispatch_get_main_queue(), ^{

        [self.collectionView reloadData]; 

    });

    dispatch_sync(dispatch_get_main_queue(), ^{

        [self.activityView stopAnimating]; // after collectionView is updated

    });

});

答案 1 :(得分:2)

除非文档明确声明可以,否则不能在后台线程上调用UIKit操作。

在任何情况下,你的问题都不应该仅仅通过在后台线程上抛出东西来解决。

你说自己,由于某种原因,加载线程花费的时间太长。为什么不在仪器中使用时间分析器来找出原因?

您可能会发现问题是您每次都在创建一个全新的图像视图并将其添加为单元格背景视图。

创建,添加和删除视图是一项昂贵的操作,滚动时不应执行此操作。您的自定义集合视图单元格应该已经具有图像视图,您已在故事板或自定义init方法中添加该图像视图,并为其创建了插座或属性。不使用子类化单元格是非常不寻常的,因为基本单元格在内容视图中没有任何内容。

填充单元格时,只需将图像视图的图像属性设置为存储的图像即可。这应该足够快,你不需要一个微调器。

从你的评论中,听起来你也有这些问题:

  • 您使用的图像太大了。要在列表中显示,您必须使用大小合适的缩略图
  • 您正在模拟器上进行性能测试。这与设备上的真实应用程序性能无关。内存情况完全不同,事物的速度可能更快或更慢,具体取决于操作(通常,基于CPU的速度更快,但基于GPU的速度更慢)。

答案 2 :(得分:1)

而不是dispatch_async,请尝试在主队列上使用dispatch_sync for _spinnerView.hidden = YES;

答案 3 :(得分:0)

这里的问题似乎是@jrturton在他的回答中提到的照片大小。 我缩短了大小(大约10磅的KB)并且工作顺利。