卸载 UICollectionview 并重新加载?

Posted

技术标签:

【中文标题】卸载 UICollectionview 并重新加载?【英文标题】:Unload UICollectionview and reload? 【发布时间】:2013-06-20 11:42:36 【问题描述】:

尝试在 ios 中重新加载 UICollectionview 时遇到问题。

我用它来显示游戏中的关卡。

collectionview 由 10 个单元格组成。单元格的内容取决于关卡是否解锁。如果关卡解锁,单元格会显示关卡(自定义 UIView),否则会显示图像。 我必须创建单独的单元格标识符才能使其正常工作,并且一切都在加载时完美显示。

我的问题是当用户玩一个解锁的关卡然后解锁下一个关卡时。当用户从游戏视图导航回到关卡选择视图时,单元格没有正确重新加载(只是在自定义视图应该是空的位置显示,图像正确显示)。

我尝试在 viewWillAppear 中卸载带有级别的数组,然后调用 [collectionview reloadData];,然后加载级别并再次重新加载 collectionview,但这没有帮助。

如何清空整个 collectionview 并在显示视图时重新创建单元格标识符?

谢谢

-编辑!用代码更新 -

-(void)viewWillAppear:(BOOL)animated 
[super viewWillAppear:YES];

levelsArray = nil;
puzzlesArray = nil;

levelsArray = [[NSMutableArray alloc]init];
puzzlesArray = [[NSMutableArray alloc]init];

[collectionView reloadData];

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"puzzles"];
puzzlesArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];

if ([puzzlesArray count] == 0) 
    [self.navigationController popViewControllerAnimated:YES];

else 
    NSLog(@"%i puzzles loaded", [puzzlesArray count]);

    //Get alle puzzles for the current category
    for (Puzzle *puzzle in puzzlesArray) 

        if ([[[NSUserDefaults standardUserDefaults]objectForKey:@"Category"] isEqualToString:[puzzle categoryName]]) 
            [levelsArray addObject:puzzle];
        

    



NSLog(@"View will appear");
[collectionView reloadData];

并且在单元格中的索引路径中的项目

    - (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; 

    BOOL isUnlocked = [self isPuzzleUnlocked:[indexPath row]];

    if ([[NSUserDefaults standardUserDefaults]boolForKey:@"u"] == YES) 
        isUnlocked = YES;
    

    [self.collectionView registerNib:[UINib nibWithNibName:@"CVCell" bundle:nil] forCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d", kCellReuseIdentifier, indexPath.row]];

    CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d", kCellReuseIdentifier, indexPath.row] forIndexPath:indexPath];

[cell setPuzzleInfo:[levelsArray objectAtIndex:[indexPath row]] unlocked:isUnlocked];

        return cell;


【问题讨论】:

您说“自定义视图”是空的,但“图像显示正确”。我不知道如何调和这两种说法。但在回答您的问题时,reloadData 正确的技术。我会在您的各种UICollectionViewDataSource 中放入日志语句或调试断点,并确认正在报告正确的值。此集合视图最初是否正常工作,但在“解锁”关卡后无法正常工作? 感谢您的评论罗。很抱歉有任何混淆,但这就像假设在重新加载时更改的单元格没有正确更改。我曾尝试对数据进行 NSLog,它是正确的。但是,当单元格在视图 WillAppear 上未“重新创建”时创建时,似乎是这样。退出视图并再次打开时,它们会正确显示。所以看起来问题是单元格仍在内存中并且没有被重新加载? 通常您会在viewWillAppearviewDidAppear 中编写调用reloadData 的代码(在调用super 之后)。再说一遍,我将日志语句放在numberOfItemsInSectioncellForItemAtIndexPath 中,这样您就可以确认当视图重新出现时reloadData 被正确调用,因此您可以在那时检查模型结构的各种值. 【参考方案1】:

符合 Rob 的建议。

-(void)viewWillAppear 
   [super viewWillAppear];
   [self.collectionView reloadData]; 

cellForItemAtIndexPath 中,您应该简单地检查项目是否已解锁并显示正确的图像或自定义单元格。

就是这样。绝对不需要重新创建集合视图。

您可能希望尊重 MVC(模型-视图-控制器)设计模式,让您的游戏控制器和关卡控制器都可以访问为关卡建模的数据。当游戏中发生的事情解锁新关卡时,它应该更改此数据。集合视图应该在它出现之前根据这些数据重新加载。

编辑:

如果您得到与以前相同的单元格/项目,即使您 reloadData,这意味着您的配置设置不正确。关键是设置unlocked 的两个状态

EDIT2:

你的itemForRowAtIndexPath 方法都搞砸了。对registerNib 的调用根本不属于那里!它应该在初始化过程中被调用。如果您使用情节提要,则根本没有必要。

这是一个你应该使用的简单框架:

- (UICollectionViewCell *)collectionView:(UICollectionView *)cv 
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath; 

   PuzzleInfo *puzzleObject = [dataArray objectAtIndex:indexPath.row]; 
   // you can use your more complicated data structure here, but 
   // have one object, dictionary, array item, etc. that has the info you need

   NSString *identifier = puzzleObject.unlocked ? kUnlockedCell : kLockedCell;
   CVCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier
           forIndexPath:indexPath];

   if (puzzleObject.unlocked) 
      // configure the unlocked cell 
   
   else 
      // configure the locked cell
   

   return cell;

【讨论】:

感谢您的回复 Mundi,但我已经这样做了。我已在原始问题中添加了代码以显示我在做什么。我认为这可能是问题“ CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d", kCellReuseIdentifier, indexPath.row] forIndexPath:indexPath];"因为它记住了单元标识符,因此没有正确重新加载?【参考方案2】:

我修好了!

- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath; 
NSLog(@"CALLED");
BOOL isUnlocked = [self isPuzzleUnlocked:[indexPath row]];

if ([[NSUserDefaults standardUserDefaults]boolForKey:@"u"] == YES) 
    isUnlocked = YES;

int rand = arc4random() % 99001;
[self.collectionView registerNib:[UINib nibWithNibName:@"CVCell" bundle:nil] forCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d%i", kCellReuseIdentifier, indexPath.row, rand]];

CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d%i", kCellReuseIdentifier, indexPath.row, rand] forIndexPath:indexPath];
[cell setPuzzleInfo:[levelsArray objectAtIndex:[indexPath row]] unlocked:isUnlocked];

    return cell;

不是一个非常有效的内存解决方案(或优雅),但它有效。向每个单元格添加一个随机数会强制每次重新创建它。只要我在collectionview中只有10个单元格,我认为就可以了..

感谢您的所有帮助:]

【讨论】:

这不是一个好的解决方案,至少是一个“修复”。即使它现在看起来有效,它也一定会崩溃。您正在 cellForItem 中的 hoc 处创建随机单元格标识符...有关解释,请参阅我的修订答案。 嗨 Mundi,是的,我知道它现在是一个理想的解决方案。问题是你的答案并没有解决问题。不知道是不是collectionview的bug,但是数据是正确的,但是显示错误。这修复了它,因为重新创建了单元标识符。当我对已锁定的未锁定数据执行 NSLog 时,它显示正确,但未在 [colletiionview reloadData] 中重新加载;我不明白为什么这会中断?我正在使用 ARC 并且每次都重新创建单元格应该不是问题吗?性能是唯一的问题,但只有 10-15 个单元格不成问题。 在这种情况下,创建随机小区标识符仍然是荒谬的。只是不要出队,你有同样的效果。 你好,可以给我“isPuzzleUnlocked”方法吗?@CCDEV

以上是关于卸载 UICollectionview 并重新加载?的主要内容,如果未能解决你的问题,请参考以下文章

即使在删除部分数据并重新加载 UICollectionView 后,部分标题仍然存在

重新加载和调用requestImageForAsset时UICollectionView闪烁

如何仅重新加载 UICollectionView 的可见部分?

UICollectionView 不重新加载数据

重新加载后无法取消选择 UICollectionView 单元格

UICollectionView 单元格在可见时不断重新加载