首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PopViewController奇怪行为

PopViewController奇怪行为
EN

Stack Overflow用户
提问于 2013-12-02 11:26:25
回答 5查看 4.3K关注 0票数 3

由于一个奇怪的请求,我试图拒绝,但它没有工作,我不得不覆盖导航栏的背后按钮。

我做了一个定制的UINavigationController子类,并黑掉了- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item方法。

这是我的代码:

代码语言:javascript
复制
@interface CustomUINavigationController ()

@end

@implementation CustomUINavigationController


#pragma mark - UINavigationBar delegate methods

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {

    if ([[self.viewControllers lastObject] isKindOfClass:[ViewController1 class]]) {
        ViewController1 *vc1 = (ViewController1 *)[self.viewControllers lastObject];
        [vc1 handleBackAction];
        if (vc1.canPopVC == YES) { 
            [self popViewControllerAnimated:YES];
            return YES;
        } else {
            return NO;
        }
    }

    [self popViewControllerAnimated:YES];
    return YES;
}

@end

除了我以编程方式弹出一个viewController之外,所有这些都很好。每当我想在说到pop之后执行推送时,这个应用程序就会崩溃。转NSZombie on,显示当以编程方式弹出一个viewController时,它的父viewController将被取消分配。此时,定制backButton并不是一个选项,因为它将失去本机iOS 7的popViewController功能。

撞车日志:

代码语言:javascript
复制
*** -[ContactsDetailViewController performSelector:withObject:withObject:]: message sent to deallocated instance 0x1806b790
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-12-02 11:37:33

我不是百分之百确定,但我认为您不应该真的在那个委托方法中弹出视图控制器。

“应该”委托方法通常不会做一些事情。他们只是断言某件事应该做还是不该做。

把你的方法改成这个..。

代码语言:javascript
复制
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {

    if ([[self.viewControllers lastObject] isKindOfClass:[ViewController1 class]]) {
        ViewController1 *vc1 = (ViewController1 *)[self.viewControllers lastObject];
        [vc1 handleBackAction];
        if (vc1.canPopVC == YES) { 
            return YES;
        } else {
            return NO;
        }
    }

    return YES;
}

看看能不能用。

我所做的就是删除popViewController调用。

编辑-如何添加自定义回退按钮

UIBarButtonItem的一个分类里..。

代码语言:javascript
复制
+ (UIBarButtonItem *)customBackButtonWithTarget:(id)target action:(@SEL)action
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setBackgroundImage:[UIImage imageNamed:@"Some image"] forState:UIControlStateNormal];
    [button setTitle:@"Some Title" forState:UIControlStateNormal];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];

    UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:button];

    return barButtonItem;
}

现在只要你想设置一个自定义的后退按钮就用..。

代码语言:javascript
复制
UIBarButtonItem *backButton = [UIBarButtonItem customBackButtonWithTarget:self action:@selector(backButtonPressed)];
票数 3
EN

Stack Overflow用户

发布于 2014-09-28 10:53:09

(我上一篇文章完全错了。这是一个完整的重写,有一个适当的解决方案。)

当我选择删除一些代码时会弹出这种行为,当我转换到ARC时会产生警告--我认为这些代码没有被调用。

这里是情况:

如果将navigationBar:shouldPopItem:隐藏在UINavigationController的子类中,那么当用户触摸NavBar的BACK按钮时,将不会弹出当前的视图控制器。但是,如果直接调用popViewControllerAnimated:,则仍将调用navigationBar:shouldPopItem:,视图控制器将弹出。

这里是为什么当用户触摸后退按钮时视图控制器无法弹出的原因:

UINavigationController有一个名为navigationBar:shouldPopItem:的隐藏方法。当用户单击“后退”按钮时,将调用此方法,当用户单击“后退”按钮时,该方法通常会调用popViewControllerAnimated:

当您隐藏navigationBar:shouldPopItem:时,不会调用超类的实现,因此不会弹出ViewController。

为什么不应该在子类“popViewControllerAnimated: navigationBar:shouldPopItem:**:**”中调用

如果在popViewControllerAnimated:中调用navigationBar:shouldPopItem:,当您单击NavBar上的BACK按钮时,您将看到您想要的行为:您可以确定是否要弹出,如果愿意,视图控制器会弹出。

但是,如果直接调用popViewControllerAnimated:,最终将弹出两个视图控制器:一个来自对popViewControllerAnimated:的直接调用,另一个来自添加到navigationBar:shouldPopItem:中的调用。

我认为是安全的解决方案:

您的自定义导航控制器应该如下所示:

代码语言:javascript
复制
@interface CustomNavigationController : UINavigationController <UINavigationBarDelegate> 
{
    // .. any ivars you want
}
@end

您的实现应该包含如下代码:

代码语言:javascript
复制
// Required to prevent a warning for the call [super navigationBar:navigationBar shouldPopItem:item]
@interface UINavigationController () <UINavigationBarDelegate>
@end


@implementation CustomNavigationController

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
    BOOL rv = TRUE;

    if ( /* some condition to determine should NOT pop */ )
    {
        // we won't pop
        rv = FALSE;

        // extra code you might want to execute ...
    } else
    {
        // It's not documented that the super implements this method, so we're being safe
        if ([[CustomNavigationController superclass]
                instancesRespondToSelector:@selector(navigationBar:shouldPopItem:)])
        {
            // Allow the super class to do its thing, which includes popping the view controller 
            rv = [super navigationBar:navigationBar shouldPopItem:item];

        }
    }

    return rv;
}
票数 14
EN

Stack Overflow用户

发布于 2013-12-02 11:50:46

我建议采取完全不同的方法。

为要在导航堆栈上推送的视图控制器创建一个基类。在viewDidLoad方法中,将自定义按钮设置为navigationItemleftBarButtonItem,并添加一个-backAction:,该-backAction:调用导航控制器的popViewControllerAnimated:方法。

这样,您就不会关心一些事情,比如失去UINavigationController的功能,比如向pop滑动,并且根本不必覆盖navigationBar:shouldPopItem:方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20327165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档