Как сделать некоторые вещи в 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
}