Iphone navigationController: дождитесь ответа uialertview перед тем, как выйти из текущего представления

У меня есть представление с кнопкой "Назад", управляемой контроллером навигации, и я хочу проверить, был ли файл сохранен, когда пользователь нажимает кнопку "Назад". Если файл был сохранен, вы вернетесь в предыдущее представление, иначе uialertview спросит вас, хотите ли вы сохранить файл или нет.

Итак, я сделал это, но вид исчез, и появится предупреждение.

-(void)viewWillDisappear:(BOOL)animated {
if(!self.fileSaved){
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Save the file?"  delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil];
    [alert show];
    [alert release];
}
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
    case 0:
        NSLog(@"NO");
        break;
    case 1:
        NSLog(@"yes");
        break;
    default:
        break;
}
}

Ответ 1

Когда вызывается viewWillDisappear, это уже слишком поздно. Вы должны перехватить кнопку "Назад" ранее. Я никогда этого не делал, но мое предложение состоит в том, чтобы установить делегат в свойстве navigationBar в методе viewDidAppear:

// save the previous delegate (create an ivar for that)
prevNavigationBarDelegate = self.navigationController.navigationBar.delegate;

self.navigationController.navigationBar.delegate = self;

Не забудьте установить его обратно в viewWillDisappear:

self.navigationController.navigationBar.delegate = prevNavigationBarDelegate;

Затем перехватите метод shouldPopItem:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
     if(!self.fileSaved) {
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Save the file?"  delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil];
         [alert show];
         [alert release];

         return NO;
     }

   if ([prevNavigationBarDelegate respondsToSelector:@selector(navigationBar:shouldPopItem:)]) 
      return [prevNavigationBarDelegate navigationBar:navigationBar shouldPopItem:item];

   return YES; 
}

И в обработчике YES для диалога вручную введите контроллер:

[self.navigationController popViewController:YES];

Ответ 2

Для этого необходимо подклассифицировать UINavigationController. Затем переопределить - (BOOL) navigationBar: (UINavigationBar *) navigationBar shouldPopItem: (UINavigationItem *) item. Вы должны настроить пользовательский протокол делегирования, который будут приняты вашими контроллерами представлений, и, если вы позволите ему поп, вызвать ваш [super navigationBar shouldPopItem:], иначе вернуть НЕТ указанному выше методу.

Ответ 3

Не было бы проще просто добавить элемент левой кнопки, как показано ниже:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(saveThisDate)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];

Ответ 4

Чтобы следить за благородным ответом, и, как пояснил Джон, лучший способ - подкласс UINavigationController.

Самый простой способ и быстрый способ добиться этого:

  • Измените класс вашего контроллера навигации в Interface Builder, чтобы наследовать от CustomNavigationControllerDelegate

Пользовательский класс навигации

  1. Внедрить протокол CustomNavigationControllerDelegate в вашем UIViewController

@interface YourViewController <CustomNavigationControllerDelegate>

#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {

    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:cancel otherButtonTitles:ok, nil];
    alert.tag = kpopup_back;
    [alert show];

    return NO;
}
  1. Зарегистрируйте свой контроллер в качестве делегата

#pragma mark - viewWillAppear - (void) viewWillAppear:(BOOL)animated { ((CustomNavigationController*)self.navigationController).customDelegate = self; }

  1. Наконец-то и важная часть, УДАЛИТЕ делегата (чтобы избежать повторного запуска самого себя в поп-музыке) и поместите контроллер самостоятельно в UIAlertViewDelegate

case kpopup_back : { if(buttonIndex != 0) //OK { ((CustomNavigationController*)self.navigationController).customDelegate = nil; [self.navigationController popViewControllerAnimated:YES]; } } break;

Он работает безупречно на моей стороне, надеюсь, что это может помочь.


Вот источники:

CustomNavigationControllerDelegate.h

#import <UIKit/UIKit.h>

@protocol CustomNavigationControllerDelegate <NSObject>
@optional
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
@end

@interface CustomNavigationController : UINavigationController

@property (nonatomic, retain) id<CustomNavigationControllerDelegate> customDelegate;

@end

CustomNavigationControllerDelegate.m

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end

@implementation CustomNavigationController

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

    if (_customDelegate && [_customDelegate respondsToSelector:@selector(navigationBar:shouldPopItem:)]) {
        return [_customDelegate navigationBar:navigationBar shouldPopItem:item];
    }

    return YES;
}

@end