0

我用 Storyboards/Segues 和 UIViewController 容器构建了一个自定义的 UITabBarController。这是一个链接:https ://github.com/mhaddl/MHCustomTabBarController

将由 Container 呈现的 UIViewController 存储在 NSMutableDictionary 中(键是 segue 的标识符)。一切正常,直到我回到之前介绍的 ViewController 为止。此时“dealloc”在这个 ViewController 被呈现之前被调用。

如何防止“dealloc”被调用,以便它可以用于取消订阅通知和 nil 委托。

MHCustomTabBarController:

    @implementation MHCustomTabBarController {
    NSMutableDictionary *_viewControllersByIdentifier;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    _viewControllersByIdentifier = [NSMutableDictionary dictionary];
}

-(void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    if (self.childViewControllers.count < 1) {
        [self performSegueWithIdentifier:@"viewController1" sender:[self.buttons objectAtIndex:0]];
    }
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    self.destinationViewController.view.frame = self.container.bounds;
}



#pragma mark - Segue

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

    if (![segue isKindOfClass:[MHTabBarSegue class]]) {
        [super prepareForSegue:segue sender:sender];
        return;
    }

    self.oldViewController = self.destinationViewController;

    //if view controller isn't already contained in the viewControllers-Dictionary
    if (![_viewControllersByIdentifier objectForKey:segue.identifier]) {
        [_viewControllersByIdentifier setObject:segue.destinationViewController forKey:segue.identifier];
    }

    for (UIButton *aButton in self.buttons) {
        [aButton setSelected:NO];
    }

    UIButton *button = (UIButton *)sender;
    [button setSelected:YES];
    self.destinationIdentifier = segue.identifier;
    self.destinationViewController = [_viewControllersByIdentifier objectForKey:self.destinationIdentifier];


}

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if ([self.destinationIdentifier isEqual:identifier]) {
        //Dont perform segue, if visible ViewController is already the destination ViewController
        return NO;
    }

    return YES;
}

#pragma mark - Memory Warning

- (void)didReceiveMemoryWarning {
    [[_viewControllersByIdentifier allKeys] enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
        if (![self.destinationIdentifier isEqualToString:key]) {
            [_viewControllersByIdentifier removeObjectForKey:key];
        }
    }];
}

@end

MHTabBarSegue:

@implementation MHTabBarSegue
- (void) perform {
    MHCustomTabBarController *tabBarViewController = (MHCustomTabBarController *)self.sourceViewController;
    UIViewController *destinationViewController = (UIViewController *) tabBarViewController.destinationViewController;

    //remove old viewController
    if (tabBarViewController.oldViewController) {
        [tabBarViewController.oldViewController willMoveToParentViewController:nil];
        [tabBarViewController.oldViewController.view removeFromSuperview];
        [tabBarViewController.oldViewController removeFromParentViewController];
    }


    destinationViewController.view.frame = tabBarViewController.container.bounds;
    [tabBarViewController addChildViewController:destinationViewController];
    [tabBarViewController.container addSubview:destinationViewController.view];
    [destinationViewController didMoveToParentViewController:tabBarViewController];
}

@end
4

1 回答 1

3

“此时“dealloc”在这个 ViewController 出现之前被调用。” ——不,不是。Dealloc 在一个永远不会出现在屏幕上的控制器上被调用,而不是你最初来自或将要返回的那个控制器。segue 的设置方式,以及在字典中保留对控制器的引用的事实,意味着它们永远不会被释放。Segues(除了展开)总是实例化新的视图控制器,所以发生的事情是当您单击第一个选项卡时会创建一个新的实例,比如说 VC1(并且触发了一个 segue),但是您从不对该控制器执行任何操作(这将是自定义 segue 类中的 self.destinationViewController ),因此一旦执行方法退出,它就会被释放。

根据您设置任何委托或通知观察者的位置,这可能不是问题——创建的这个控制器,然后立即解除分配永远不会调用它的 viewDidLoad 方法,所以如果你在 viewDidLoad 中做这些事情,它们将永远不会发生对于这个瞬态视图控制器。

如果您不希望这种情况发生,那么您需要在不使用 segue 的情况下在代码中进行转换。

于 2013-11-10T07:21:30.407 回答