未调用UINavigationControllerDelegate方法(github上的演示代码)

时间:2012-04-24 16:23:45

标签: cocoa-touch delegates uinavigationcontroller

弹出到不支持当前方向的视图控制器时未调用的UINavigationControllerDelegate方法。

我有一个UINavigationController作为我的应用程序的根视图控制器(我的Storyboard中的初始视图控制器)。

假设我将ViewController A推送到方向:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

因此我们不支持任何横向模式。最重要的是,让我们使用代码推送另一个ViewController:

@interface B : UIViewController <UINavigationControllerDelegate>
@end

@implementation B
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;   // any orientation supported
}

- (void)viewDidLoad {
    [super viewDidLoad];

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    UINavigationController *nc = (UINavigationController*)appDelegate.window.rootViewController;
    nc.delegate = self;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // not always called...
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    // not always called...
}
@end

现在,如果我的iPhone是纵向的,我将视图控制器B推到A顶部,通过一些触摸事件,然后触摸导航栏中的“后退”按钮,一切都很好,并调用委托方法(我做那里的一些东西)。

但是,如果,当我正在查看视图B时,我旋转到横向,然后点击后退按钮,那些委托方法不会被调用!!如果有时调用方法而不调用其他方法,那么为UINavigationController设置委托有什么意义呢?当然我做错了。

我尝试将委托放在其他类中,比如AppDelegate或我的MainView,没有任何改变。

有什么想法吗?

演示代码: git://github.com/malaba/NavBarTest.git

从基本的Master-Detail模板中进行修改,如上所述。

如何表明我的观点?这是一步一步:

  1. 在主视图中添加一些行(+右上角)
  2. 然后触摸一行以转到详细信息视图
  3. 请参阅显示的登录输出
  4. 点击后退按钮(标有“Master”),再次显示日志。
  5. 现在尝试在详情视图中旋转iPhone(或模拟器),然后“返回”并看到无日志出现?!

2 个答案:

答案 0 :(得分:2)

嗨,这对我来说也是一个棘手的问题,直到我看到这个想法:http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller

当NavigationController和TopViewController具有相同的方向时,IOS使用以下代码(monotouch)创建以下调用序列

  • SomeTopViewController ViewWillDisappear
  • WillShowViewController viewController:新的TopViewController
  • SomeTopViewController ViewDidDisappear
  • DidShowViewController viewController:新的TopViewController

当NavigationController和TopViewController具有不同的方向时,导航控制委托是,如您所述。因此呼叫顺序是:

  • SomeTopViewController ViewWillDisappear
  • SomeTopViewController ViewDidDisappear

以下代码通过覆盖NavigationController的PopViewControllerAnimated来重现ios调用序列:

public class MyNavigationControllerDelegate : UINavigationControllerDelegate {
  public MyNavigationControllerDelegate( ) : base() {}

  public bool WasCalled {get;set;}  // flag that we use to track whether iOS calls the handlers or we have to 

  public override void WillShowViewController( UINavigationController navigationController, UIViewController viewController, bool animated ) {
    Console.WriteLine( "WillShowViewController viewController: {0}", viewController.GetType() );
    WasCalled = true;  // signal that we have been called
    //.….. do your stuff
  }

  public override void DidShowViewController( UINavigationController navigationController, UIViewController viewController, bool animated ) {
    Console.WriteLine( "DidShowViewController viewController: {0}", viewController.GetType() );
    //.….. do your stuff
  }
}

public partial class MyNavigationController : UINavigationController {
  MyNavigationControllerDelegate navigationControllerDelegate;

  public override void ViewDidLoad() {
    base.ViewDidLoad();
    navigationControllerDelegate = new MyNavigationControllerDelegate( viewSelectionControl );
    Delegate = navigationControllerDelegate;
  }

public override UIViewController PopViewControllerAnimated( bool animated ) {
  Console.WriteLine( "PopViewControllerAnimated TopViewController.GetType: {0}", TopViewController.GetType() );
  navigationControllerDelegate.WasCalled = false;   // reset flag before we start the popsequence

  UIViewController ctrl = base.PopViewControllerAnimated( animated );

  AppDelegate.MainWindow.BeginInvokeOnMainThread( delegate {
    if( !navigationControllerDelegate.WasCalled )  {   // if iOS did not call the delegate handler then we must do it
      Delegate.WillShowViewController( this, TopViewController, animated );
      navigationControllerDelegate.WasCalled = false;  // reset flag to be used in the next DidShowViewController step of the popsequence
      }
  } );

  Thread t = new Thread( () => RunPop(animated) );
  tt.Start();

  return ctrl;
}

void RunPop(bool animated) {
  Thread.Sleep( 500 );
  AppDelegate.MainWindow.BeginInvokeOnMainThread( delegate {
    if( !navigationControllerDelegate.WasCalled ) {  // if iOS did not call the delegate handler then we must do it
      Delegate.DidShowViewController(this,TopViewController,animated);
    }
  } );
}

}

答案 1 :(得分:1)

由Kaspar回答,这是我在Obj-C中的代码。

·H:

@interface ProperNavigationController : UINavigationController

@end

@interface ProperNavigationControllerDelegate : NSObject <UINavigationControllerDelegate>
@property (assign, nonatomic) BOOL wasCalled;
@end

的.m:

#import "ProperNavigationController.h"

@interface ProperNavigationController ()
@property (strong, nonatomic) id<UINavigationControllerDelegate> oldDelegate;
@property (strong, nonatomic) ProperNavigationControllerDelegate *myDelegate;
@end

@implementation ProperNavigationController
@synthesize oldDelegate = _oldDelegate;
@synthesize myDelegate = _myDelegate;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.oldDelegate = self.delegate;
    self.myDelegate = [ProperNavigationControllerDelegate new];
    self.delegate = self.myDelegate;
}

- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
    self.myDelegate.wasCalled = FALSE;

    UIViewController *vc = [super popViewControllerAnimated:animated];

    if (!self.myDelegate.wasCalled) {
        // if iOS did not call the delegate handler then we must do it
        [self.myDelegate navigationController:self willShowViewController:self.topViewController animated:animated];
        [self.myDelegate navigationController:self didShowViewController:self.topViewController animated:animated];
    }

    return vc;
}

@end

@implementation ProperNavigationControllerDelegate
@synthesize wasCalled = _wasCalled;     // flag that we use to track whether iOS calls the handlers or we have to 

- (id)init {
    if (self = [super init]) {
       _wasCalled = FALSE; 
    }
    return self;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    ProperNavigationController *nc = (ProperNavigationController *)navigationController;
    [nc.oldDelegate navigationController:navigationController willShowViewController:viewController animated:animated];
    self.wasCalled = TRUE;  // signal that we have been called
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    ProperNavigationController *nc = (ProperNavigationController *)navigationController;
    [nc.oldDelegate navigationController:navigationController didShowViewController:viewController animated:animated];
}

@end

它有效。

你怎么看?我们应该填写错误报告吗?