代码之家  ›  专栏  ›  技术社区  ›  Ben Collins

从UINavigationController堆栈中弹出UITableViewController时是否有特殊行为?

  •  3
  • Ben Collins  · 技术社区  · 15 年前

    我在一个标签栏应用程序中遇到了一个奇怪的看起来像是过度发布的问题。我对这个问题描述的复杂性表示歉意。希望一个小的示例代码会有帮助。

    我有我的申请代表 MyAppDelegate 设置为 UITabBarControllerDelegate :

    - (BOOL)tabBarController:(UITabBarController *)tabBarControllerIn shouldSelectViewController:(UIViewController *)viewController {
        return YES;
    }
    
    - (void)tabBarController:(UITabBarController *)tabBarControllerIn didSelectViewController {
        if ([viewController isKindOfClass:[UINavigationController class]]) {
            UINavigationController *navController = (UINavigationController *)viewController;
            [navController popToRootViewControllerAnimated:NO];
        }
    }
    

    选项卡栏视图设置为 UINavigationController 每5个标签。根视图控制器(调用它 CrashingViewController )在 飞行控制器 为表4配置的派生自 UIViewController 并符合 UITableViewDataSource UITableViewDelegate 支持 UITableView 子视图,这只是一个4行表,每个单元格允许用户导航到另一个视图。在 -[UITableViewDelegate tableView:didSelectRowAtIndexPath:] :

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        ASubViewController1 *svc1;
        ASubViewController2 *svc2;  // this one inherits from UITableViewController;
        ASubViewController3 *svc3;
        ASubViewController4 *svc4;
    
        switch (indexPath.row) {
            case 1:
                svc1 = [[ASubViewController1 alloc] init];
                [self.navigationController pushViewController:svc1 animated:YES];
                [svc1 release];
                break;
            case 2:
                svc2 = [[ASubViewController2 alloc] init];
                [self.navigationController pushViewController:svc2 animated:YES];
                [svc2 release];  // if I comment this out, I avoid the problem described
                break;
            /* case 3 and 4 are exactly like the previous two */
            default:
                break;
        }
    }
    

    结果是:如果用户选择选项卡栏的第4个选项卡,则 撞车控制器 显示的视图。然后,用户点击其表中的第二个单元格,该单元格推送 ASubViewController2 在导航堆栈上到现在为止,一直都还不错。现在,如果用户点击选项卡栏上的另一个选项卡,则会显示另一个视图控制器的视图。如果用户再次点击第四个选项卡,则 飞行控制器 配置为该选项卡的根视图控制器将弹出其所有项并显示 它的 根视图控制器。正是在这期间,应用程序崩溃了,因为一路上某个地方的UIKit框架调用了[ASubViewController2 respondsToSelector:]on svc2 在它被释放之后。

    我遇到的困难是:为什么当用户导航到 ASubViewController2系统 ,但其他的都没有 ASubViewController* s?还有,如果我不能释放 svc2号 ,不会发生崩溃-所以肯定是双重释放 svc2号 在某个地方,我只是不知道发生在哪里。 svc2号 是一个方法局部变量,我在分配后立即释放它。做一个 UITableViewController 当从导航控制器堆栈中弹出时,其行为与 uiview控制器 ? 我还缺什么吗?

    我确信我只是遗漏了一些有很好的记录或者直接的东西,但是我已经观察了足够长的时间,以至于有了一些盲点。

    更新 :

    我确实启用了nszombiesenable。下面是控制台中给出的消息:

    *** -[ASubViewController2 respondsToSelector:]: message sent to deallocated instance 0xe345cd0
    

    以及回溯:

    #0  0x02a18fa7 in ___forwarding___ ()
    #1  0x02a18e72 in __forwarding_prep_0___ ()
    #2  0x003e69be in -[UITableView(UITableViewInternal) _spacingForExtraSeparators] ()
    #3  0x003ede94 in -[UITableView(_UITableViewPrivate) _adjustExtraSeparators] ()
    #4  0x003e6743 in -[UITableView layoutSubviews] ()
    #5  0x027b9481 in -[CALayer layoutSublayers] ()
    #6  0x027b91b1 in CALayerLayoutIfNeeded ()
    #7  0x027b22e0 in CA::Context::commit_transaction ()
    #8  0x027b2040 in CA::Transaction::commit ()
    #9  0x027e2ebb in CA::Transaction::observer_callback ()
    #10 0x02a88f4b in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
    #11 0x02a1db27 in __CFRunLoopDoObservers ()
    #12 0x029e6ce7 in __CFRunLoopRun ()
    #13 0x029e6350 in CFRunLoopRunSpecific ()
    #14 0x029e6271 in CFRunLoopRunInMode ()
    #15 0x0329200c in GSEventRunModal ()
    #16 0x032920d1 in GSEventRun ()
    #17 0x00380af2 in UIApplicationMain ()
    #18 0x0000226a in main (argc=1, argv=0xbfffef64) at ~/main.m:16
    

    更新2 :

    这个 dealloc 方法 ASubViewController2系统 被召唤 svc2号 在用户第二次点击tab 4之后,在输出僵尸消息之前。我的代码都不在解除锁定的代码路径中。

    1 回复  |  直到 15 年前
        1
  •  5
  •   Vladimir    15 年前

    我也遇到过类似的问题。视图控制器似乎已经被释放,但是它的表视图仍然调用被释放的视图控制器的委托。只需在view controller的dealloc中添加以下行或类似行:

    self.tableView.delegate=无; self.tableView.dataSource=nil;

    对我有帮助!