2013-06-20 61 views
0

我尝试在iOS中重新加载UICollectionView时有一个probem。卸载UICollectionView并重新加载?

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

collectionview由10个单元组成。单元格的内容取决于级别是否解锁。如果关卡解锁,那么单元显示关卡(一个自定义的UIView),否则显示一个图像。 我不得不为此创建单独的单元格标识符,并且所有内容在加载时都完美显示。

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

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

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

谢谢

-EDIT!更新了CODE -

-(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; 

} 
+1

你说的“自定义视图”是空的,但“图像正确显示” 。我不知道如何调和这两个陈述。但在回答你的问题时,'reloadData'是正确的技术。我会在各种'UICollectionViewDataSource'中放入日志语句或调试断点,并确认正在报告正确的值。这个集合视图最初是否正确工作,但在“解锁”一个关卡后不正确? – Rob

+0

感谢您的评论罗布。 对不起,任何困惑,但它就像是重新加载时更改的单元格没有正确更改。 我试图NSLog的数据,它是正确的。但是,看起来像是当单元格被创建后,一旦它没有被“重新创建”,就会出现WillAppear。它们在退出视图并再次打开时正确显示。所以看起来问题是单元格仍然在内存中而不是重新加载? – CCDEV

+0

通常你会在你的'viewWillAppear'或'viewDidAppear'中编写代码,它会调用'reloadData'(在调用'super'后)。为了重复我自己,我会将log语句放在'numberOfItemsInSection'和'cellForItemAtIndexPath'中,这样您就可以确认reloadData在视图重新出现时被正确调用,因此您可以在该点检查模型结构的各种值。 – Rob

回答

1

在符合罗布的建议。

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

cellForItemAtIndexPath你应该简单地检查,如果该项目被解锁与否,并显示适当的图像或自定义单元格。

就是这样。这肯定是而不是重新创建收集视图。

您可能希望通过向游戏控制器和级别控制器访问模型级别的数据来实现MVC(模型 - 视图 - 控制器)设计模式。当游戏中发生的事情解锁一个新的水平时,它应该改变这个数据。集合视图应该在它出现之前根据这些数据重新加载自己。

编辑:

如果你得到同样的细胞/项目,如即使你reloadData之前,这意味着你的配置不正确设置。关键是设置两个状态unlocked明确 - reloadData将更新项目,如果它已更改。

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; 
} 
+0

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

-3

我定了!

- (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; 

}

不是一个非常内存effecient溶液(或优雅),但它的作品。向每个单元格添加一个随机数字将强制每次重新创建它。只要我只有10个细胞中的CollectionView我认为这将是确定..

感谢您的帮助:]

+0

这不是一个好的解决方案,至少所有的“修复”。即使现在看来工作,它也一定会突破。您正在cellForItem中创建随机单元格标识符...请参阅我的修订答案以获取解释。 – Mundi

+0

嗨蒙迪,是的,我知道它现在是一个理想的解决方案。问题是你的答案没有解决问题。不知道它是否是一个collectionview错误,但数据是正确的,但显示错误。这修复了它,因为单元标识符被重新创建。当我做一个锁定的解锁数据的NSLog时,它显示正确,但不会在[collectiionview reloadData]中重新加载;我不明白为什么这会打破?我使用ARC并重新创建单元格不应该成为问题?性能是唯一的问题,但只有10-15个单元不成问题。 – CCDEV

+0

在这种情况下,创建随机单元标识符仍然很荒谬。只是不要出队,而且你有相同的效果。 – Mundi