ios - 在存储在 NSMutableDictionary 中并由 UIViewControllerContainment 呈现的 UIViewController 上调用 Dealloc

标签 ios objective-c uiviewcontroller dealloc containment

我已经构建了一个自定义的 UITabBarController,其中包含 Storyboards/Segues 和 UIViewController。这是它的链接:https://github.com/mhaddl/MHCustomTabBarController

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

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

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

最佳答案

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

根据您设置任何委托(delegate)或通知观察者的位置,这可能不是问题——这个创建并立即释放的 Controller 永远不会调用其 viewDidLoad 方法,因此如果您在 viewDidLoad 中执行这些操作,它们将不会这个 transient View Controller 永远不会发生。

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

关于ios - 在存储在 NSMutableDictionary 中并由 UIViewControllerContainment 呈现的 UIViewController 上调用 Dealloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19881692/

相关文章:

iphone - 如何为 UIScrollView 中的内容区域设置背景颜色?

ios - 3 秒后将 View 重定向到另一个 View

objective-c - 获取JSON字典中的所有值,而无需按键访问

iphone - 在 iOS 的动态框架中包含一个静态库

swift - 如果在应用程序终止后从通知主体启动应用程序,则打开弹出窗口

ios - iPhone 上的 URL 错误,当我在浏览器中输入它时它可以工作

objective-c - 如何触摸和拖动动画图像?这是我的动画代码 :

ios - 我应该使用 ImageView 还是 TextField?

objective-c - 将 .xib 文件添加到 UIViewController 子类?

ios - 在 UISheetPresentationController 中自定义较小的 Detents?