提示信息:"嵌套的推送动画可能导致导航栏出错"

4

我完全被卡住了。我在Stack Overflow上搜索答案,看起来每个“nested push animation can result in corrupted navigation bar”错误都有不同的问题。

请记住,我正在尝试自学如何为iOS 7编写代码。所以如果我的编程方法不理想,我很抱歉,请提供反馈。不管怎样,我正在创建一个宝可梦交换卡牌游戏百科全书应用程序,显示最近套装中的卡牌。一切正常工作,除了当我在主屏幕上选择第一行表格单元格(XY闪电火花)时。它将显示正确的表格数据,但导航栏标题不正确。而且当我选择一行时,它不会进入PokedexDetailViewController。

再次说明,其他所有主屏幕上的表格单元格均无任何问题。我还尝试了其他人在这里和github上发布的修复程序和类,但没有一个适用于我。我还重新创建了整个FlashFireViewController,仍然存在相同的问题。确保所有代码基本上与其他工作视图控制器相同。还验证了segue是从Set View Controller发出的,而不是从单元格发出的。但是,一旦它在Flash Fire View Controller中,segue就源自于单元格。

暂时无法发布图片,因此这是我的屏幕截图的专辑链接:http://imgur.com/a/Dq9py

  1. 我的storyboard设置方式。
  2. 启动应用程序后的主屏幕。
  3. 当我选择第二行(XY)时。
  4. 当我选择“超级妙蛙花EX”时。
  5. **错误。当我选择第一行(XY闪电火花)时,它会显示正确的表格数据,但不会显示正确的导航标题。
  6. 当我选择Butterfree或任何其他宝可梦时,什么也不会发生,导航标题也会消失。而且,一旦我返回,应用程序就会崩溃并停止运行。

这是TCGSetViewController.m的代码,它是主屏幕的类。

@interface TCGSetViewController ()

@end

@implementation TCGSetViewController{



 NSArray *thumbnailCell;
}

@synthesize tableView = _tableView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    thumbnailCell = [NSArray arrayWithObjects:@"XYFlashFire.png", @"XYBaseSet.png", @"BWLegendaryTreasures", @"BWPlasmaBlast.png", @"BWPlasmaFreeze.png", @"BWPlasmaStorm.png", nil];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    return [thumbnailCell count];


}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 61;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"PokemonSetCell";

    TCGSetCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil) {
        cell = [[TCGSetCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
    }

    cell.setImage.image = [UIImage imageNamed:[thumbnailCell objectAtIndex:indexPath.row]];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Conditionally perform segues, here is an example:
    if (indexPath.row == 0)
    {
        [self performSegueWithIdentifier:@"showFlashFireSet" sender:self];
    }
    if (indexPath.row == 1)
    {
        [self performSegueWithIdentifier:@"showXYBaseSet" sender:self];
    }
    else
    {
        [self performSegueWithIdentifier:@"showLegendarySet" sender:self];
    }
}

这里是FlashFireViewController.m的代码,它是第一个表格单元。

@interface FlashFireViewController ()

@end

@implementation FlashFireViewController{

    NSArray *pokemons;
    NSArray *searchResults;
}

@synthesize tableView = _tableView;

- (void)viewDidLoad
{
    [super viewDidLoad];


    Pokemon *caterpie = [Pokemon new];
    caterpie.name = @"Caterpie";
    caterpie.hitPoints = @"40 HP";
    caterpie.setNumber = @"1/106";
    caterpie.imageFile = @"1-caterpie.jpg";
    caterpie.rarity = @"COMMON";

    Pokemon *metapod = [Pokemon new];
    metapod.name = @"Metapod";
    metapod.hitPoints = @"70 HP";
    metapod.setNumber = @"2/106";
    metapod.imageFile = @"2-metapod.jpg";
    metapod.rarity = @"UNCOMMON";

    Pokemon *butterfree = [Pokemon new];
    butterfree.name = @"Butterfree";
    butterfree.hitPoints = @"130 HP";
    butterfree.setNumber = @"3/106";
    butterfree.imageFile = @"3-butterfree.jpg";
    butterfree.rarity = @"RARE";

    Pokemon *pineco = [Pokemon new];
    pineco.name = @"Pineco";
    pineco.hitPoints = @"60 HP";
    pineco.setNumber = @"4/106";
    pineco.imageFile = @"4-pineco.jpg";
    pineco.rarity = @"COMMON";

    Pokemon *seedot = [Pokemon new];
    seedot.name = @"Seedot";
    seedot.hitPoints = @"50 HP";
    seedot.setNumber = @"5/106";
    seedot.imageFile = @"5-seedot.jpg";
    seedot.rarity = @"COMMON";

    Pokemon *nuzleaf = [Pokemon new];
    nuzleaf.name = @"Nuzleaf";
    nuzleaf.hitPoints = @"80 HP";
    nuzleaf.setNumber = @"6/106";
    nuzleaf.imageFile = @"6-nuzleaf.jpg";
    nuzleaf.rarity = @"UNCOMMON";

    Pokemon *shiftry = [Pokemon new];
    shiftry.name = @"Shiftry";
    shiftry.hitPoints = @"140 HP";
    shiftry.setNumber = @"7/106";
    shiftry.imageFile = @"7-shiftry.jpg";
    shiftry.rarity = @"RARE";

    Pokemon *roselia = [Pokemon new];
    roselia.name = @"Roselia";
    roselia.hitPoints = @"60 HP";
    roselia.setNumber = @"8/106";
    roselia.imageFile = @"8-roselia.jpg";
    roselia.rarity = @"COMMON";

    Pokemon *roserade = [Pokemon new];
    roserade.name = @"Roserade";
    roserade.hitPoints = @"90 HP";
    roserade.setNumber = @"9/106";
    roserade.imageFile = @"9-roserade.jpg";
    roserade.rarity = @"UNCOMMON";

    Pokemon *maractus = [Pokemon new];
    maractus.name = @"Maractus";
    maractus.hitPoints = @"90 HP";
    maractus.setNumber = @"10/106";
    maractus.imageFile = @"10-maractus.jpg";
    maractus.rarity = @"UNCOMMON";

    pokemons = [NSArray arrayWithObjects:caterpie, metapod, butterfree, pineco, seedot, nuzleaf, shiftry, roselia, roserade, maractus, nil];

}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        return [searchResults count];

    } else {
        return [pokemons count];
    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    static NSString *pokemonTableIdentifier = @"PokemonTableCell";

    TCGPokedexCell *cell = (TCGPokedexCell *)[self.tableView dequeueReusableCellWithIdentifier:pokemonTableIdentifier];

    if (cell == nil)
    {
        cell = [[TCGPokedexCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:pokemonTableIdentifier];
    }


    Pokemon *pokemon = [pokemons objectAtIndex:indexPath.row];
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        pokemon = [searchResults objectAtIndex:indexPath.row];
    } else {
        pokemon = [pokemons objectAtIndex:indexPath.row];
    }
    cell.pokemonLabel.text = pokemon.name;
    cell.pokemonNum.text = pokemon.setNumber;
    cell.thumbnailImageView.image = [UIImage imageNamed:pokemon.imageFile];
    cell.pokemonHP.text = pokemon.hitPoints;
    cell.pokemonRarity.text = pokemon.rarity;

    return cell;

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 61;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([segue.identifier isEqualToString:@"showPokedexDetail"]) {
        NSIndexPath *indexPath = nil;
        Pokemon *pokemon = nil;

        if (self.searchDisplayController.active) {
            indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
            pokemon = [searchResults objectAtIndex:indexPath.row];
        } else {
            indexPath = [self.tableView indexPathForSelectedRow];
            pokemon = [pokemons objectAtIndex:indexPath.row];
        }

        PokedexDetailViewController *destViewController = segue.destinationViewController;
        destViewController.pokemon = pokemon;
    }
}

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
    searchResults = [pokemons filteredArrayUsingPredicate:resultPredicate];
}

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString
                               scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
                                      objectAtIndex:[self.searchDisplayController.searchBar
                                                     selectedScopeButtonIndex]]];

    return YES;
}



@end

这是我得到的精确错误代码:

在这里

2014-07-08 12:38:18.409 TCG Pokedex[37666:60b] nested push animation can result in corrupted navigation bar
2014-07-08 12:38:18.849 TCG Pokedex[37666:60b] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
2014-07-08 12:38:22.222 TCG Pokedex[37666:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't add self as subview'
*** First throw call stack:

我在你的代码中没有发现任何问题,假设TCGSetViewController中的segues都是从控制器创建的,就像你说的那样。通常当您尝试同时执行两个推送(例如一个segue和一个手动推送)时,会出现此错误,但我在您的代码中没有看到任何类似的情况。 - rdelmar
2个回答

5
您的问题很可能在TCGSetViewController.m文件中的tableView:didSelectRowAtIndexPath方法中。
您有一个由if语句跟随的if else语句。当indexPath.row == 0时,第一个if为真,执行[self performSegueWithIdentifier:@"showFlashFireSet" sender:self]。但是,代码继续执行到if else块中。您在那里有两个不同的执行块。由于indexPath.row仍为0,我们将进入else块,并执行另一个转场。
您最可能希望将其结构化为:
if (indexPath.row == 0)
{
    [self performSegueWithIdentifier:@"showFlashFireSet" sender:self];
}
else if (indexPath.row == 1) // notice the else on this line
{
    [self performSegueWithIdentifier:@"showXYBaseSet" sender:self];
}
else
{
    [self performSegueWithIdentifier:@"showLegendarySet" sender:self];
}

更好的方法是将它放入switch语句中:
NSString *segueID = nil;
switch (indexPath.row) {
    case 0:
        segueID = @"showFlashFireSet";
        break;
    case 1:
        segueID = @"showXYBaseSet";
        break;
    default:
        segueID = @"showLegendarySet";
        break;
}
[self performSegueWithIdentifier:segueID sender:self];

P.S.: 更多的评论

从iOS 5或6或7之后,dequeueReusableCellWithIdentifier:forIndexPath:保证返回一个有效的单元格,因此在调用该方法后检查cell == nil是不必要的(假设您不针对旧 iOS 版本)。

我看到您只调用了dequeueReusableCellWithIdentifier:,但这个方法有可能返回nil。 但是在您发布的代码中两次都在tableView数据源方法内调用了该方法,并且都有一个可用的indexPath,因此请利用它并删除那些if (cell == nil)检查;这很令人振奋。


谢谢您分解问题。我现在完全明白了。我还忘记了开关。我知道有更好的选择多个segue的方法。 - DREW1990

1

你可以试一下这个,我还没有亲自测试过这段代码,但它可能有效。

这里是问题所在的区域。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    /*
    // You got a problem with all these ifs and elses. 2 things are happening. 
    if (indexPath.row == 0) <----Is called
    {
        [self performSegueWithIdentifier:@"showFlashFireSet" sender:self];

    }
    if (indexPath.row == 1) <---also called
    {
        [self performSegueWithIdentifier:@"showXYBaseSet" sender:self];
    }
    else <--- this is also called. 
    {
        [self performSegueWithIdentifier:@"showLegendarySet" sender:self];
    } */



    if (indexPath.row == 0)
{
    [self performSegueWithIdentifier:@"showFlashFireSet" sender:self];
     break;
}
else if (indexPath.row == 1) // notice the else on this line
{
    [self performSegueWithIdentifier:@"showXYBaseSet" sender:self];
    break;
}
else
{
    [self performSegueWithIdentifier:@"showLegendarySet" sender:self];
     break;
}

}

感谢您的输入。我尝试了您的代码,但是“breaks”会引发错误。 - DREW1990

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接