Как сделать некоторые вещи в viewDidAppear только один раз?

Я хочу проверить панель и показать предупреждение, если оно содержит определенные значения при появлении представления. Я могу поместить код в viewDidLoad, чтобы он был вызван только один раз, но проблема в том, что представление предупреждения отображается слишком быстро. Я знаю, что могу установить таймер, чтобы отложить внешний вид оповещения, но это не очень хорошая работа, я думаю.

Я проверил вопрос iOS 7 - Разница между viewDidLoad и viewDidAppear и обнаружил, что есть один шаг для проверки наличия представления. Поэтому я задаюсь вопросом, есть ли какие-либо апи для этого?

Обновление: "только один раз" означает время жизни экземпляра контроллера представления.

Ответы

Ответ 1

Существует стандартный, встроенный метод, который вы можете использовать для этого.

Objective-C:

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

    if ([self isBeingPresented] || [self isMovingToParentViewController]) {
        // Perform an action that will only be done once
    }
}

Swift 3:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if self.isBeingPresented || self.isMovingToParentViewController {
        // Perform an action that will only be done once
    }
}

Вызов isBeingPresented имеет значение true, когда сначала отображается контроллер просмотра в результате отображения модально. isMovingToParentViewController имеет значение true, когда контроллер представления сначала помещается в стек навигации. Один из двух будет правдивым при первом появлении контроллера вида.

Не нужно иметь дело с BOOL ivars или любым другим трюком для отслеживания первого вызова.

Ответ 2

Ответы rmaddy действительно хороши, но это не решает проблему, когда контроллер представления является контроллером корневого представления контроллера навигации и всех других контейнеров, которые не передают эти флаги в свой контроллер детского представления.

Итак, в таких ситуациях я лучше всего использую флаг и потребляю его позже.

@interface SomeViewController()
{
    BOOL isfirstAppeareanceExecutionDone;
}
@end

@implementation SomeViewController

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if(isfirstAppeareanceExecutionDone == NO) {
        // Do your stuff
        isfirstAppeareanceExecutionDone = YES;
    }
}

@end

Ответ 3

Это решение будет вызывать viewDidAppear только один раз в течение жизненного цикла приложения, даже если вы создадите несколько объектов контроллера вида, это не будет вызываться через один раз. Пожалуйста, обратитесь к ответу rmaddy выше

Вы можете выполнить селектор в viewDidLoad или использовать dispatch_once_t в viewDidAppear. Если вы найдете лучшее решение, пожалуйста, поделитесь со мной. Вот как я делаю это.

- (void)viewDidLoad {
  [super viewDidLoad];
  [self performSelector:@selector(myMethod) withObject:nil afterDelay:2.0];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  static dispatch_once_t once;
  dispatch_once(&once, ^{
    //your stuff
    [self myMethod];
  });
}

Ответ 4

Если я правильно понял ваш вопрос, вы можете просто установить переменную BOOL, чтобы узнать, что viewDidAppear уже вызван, например:

- (void)viewDidAppear {
    if (!self.viewHasBeenSet) { // <-- BOOL default value equals NO

        // Perform whatever code you'd like to perform
        // the first time viewDidAppear is called

        self.viewHasBeenSet = YES; 
    }
}

Ответ 5

Читая другие комментарии (и на основе ответа @rmaddy), я знаю, что это не то, о чем попросил ОП, а для тех, кто пришел сюда из-за названия вопроса:

extension UIViewController {
    var isPresentingForFirstTime: Bool {
        return isBeingPresented() || isMovingToParentViewController()
    }
}

UPDATE

Этот метод следует использовать в viewDidAppear и viewWillAppear. (спасибо @rmaddy)

ОБНОВЛЕНИЕ 2

Этот метод работает только с модально представленными контроллерами представлений и толкаемыми контроллерами представлений. он не работает с childViewController. использование didMoveToParentViewController было бы лучше с childViewControllers.

Ответ 6

Вы можете использовать эту функцию в методе ViewDidLoad

выполнитьSelector: withObject: afterDelay:

он будет вызывать эту функцию после задержки. поэтому вам не нужно использовать какой-либо пользовательский объект таймера. и за один раз вы можете использовать

dispatch_once DCD block.Just performSelector в блоке dispatch_once он вызывается performSelector только один раз, когда ViewDidLoad вызывается

Надеюсь, что это поможет

Ответ 7

Попробуйте установить значение BOOL, когда произойдет ситуация.

@interface AViewController : UIViewController
   @property(nonatomic) BOOL doSomeStuff;
@end

@implementation AViewController
- (void) viewWillAppear:(BOOL)animated
{
    if(doSomeStuff)
    {
       [self doSomeStuff];
       doSomeStuff = NO;
    }
}

где-нибудь вы запускаете экземпляр AViewController:

AddEventViewController *ad = [AddEventViewController new];
ad.doSomeStuff = YES;

Не знаете, почему вы это делаете в ViewDidAppear? Но если вы хотите, чтобы doSomeStuff был закрыт, а soSomeStuff вызывался только один раз, вот еще одно решение:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomeStuff) name:@"do_some_stuff" object:nil];

- (void) doSomeStuff
{}

Затем опубликуйте где-нибудь:

[[NSNotificationCenter defaultCenter] postNotificationName:@"do_some_stuff" object:nil];

Ответ 8

Вы можете использовать флаг или заданный тег для просмотра как:

override func viewDidAppear(_ animated: Bool)
{
    if view.tag == 0 {
        //Your view have appeared for the first time
        //do anything here you want to do
        //when next time your view will appear these lines will be skipped
    }
    view.tag = 1
}