web-dev-qa-db-ja.com

viewDidAppearでいくつかのことを一度だけ行う方法は?

ペーストボードをチェックして、ビューが表示されたときに特定の値が含まれている場合にアラートを表示したい。コードをviewDidLoadに配置して、1回だけ呼び出されるようにすることができますが、問題はアラートビューの表示が速すぎることです。タイマーを設定してアラートの表示を延期できることはわかっていますが、これは適切な回避策ではないと思います。

私は質問 iOS 7-viewDidLoadとviewDidAppearの違い を確認しましたが、ビューが存在するかどうかを確認するためのステップが1つあることを発見しました。これを行うためのAPIはあるのでしょうか。

更新:「1回のみ」とは、ビューコントローラーインスタンスの存続期間を意味します

25
Allen

これに使用できる標準の組み込みメソッドがあります。

Objective-C:

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

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

スウィフト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になります。 2つのうちの1つは、ビューコントローラが初めて表示されたときにtrueになります。

最初の呼び出しを追跡するために、BOOL ivarsやその他のトリックに対処する必要はありません。

66
rmaddy

rmaddyの答えは本当に良いですが、ビューコントローラーがナビゲーションコントローラーのルートビューコントローラーであり、他のすべてのコンテナーがこれらのフラグを子ビューコントローラーに渡さない場合、問題は解決しません。

したがって、このような状況では、フラグを使用して後で使用するのが最善です。

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

@implementation SomeViewController

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

@end
7
BangOperator

私があなたの質問を正しく理解している場合は、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; 
    }
}
4
Lyndsey Scott

このソリューションは、ビューコントローラーの複数のオブジェクトを作成した場合でも、アプリのライフサイクル全体でviewDidAppearを1回だけ呼び出します。これは一度だけは呼び出されません。上記の rmaddyの回答を参照してください

viewDidLoadでセレクターを実行するか、viewDidAppeardispatch_once_tを使用できます。より良い解決策を見つけたら、私と共有してください。これが私のやり方です。

- (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];
  });
}
2

他のコメントを読むことによって(そして@rmaddyの回答に基づいて)、これはOPが要求したものではなく、質問のタイトルのためにここに来た人々のためにあることがわかります。

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

[〜#〜]更新[〜#〜]

このメソッドはviewDidAppearおよびviewWillAppearで使用する必要があります。 (@rmaddyに感謝)

更新2

このメソッドは、モーダル表示されたビューコントローラーとプッシュされたビューコントローラーでのみ機能します。 childViewControllerでは機能しません。 childViewControllersではdidMoveToParentViewControllerを使用する方が良いでしょう。

1
farzadshbfn

状況が発生したときに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が1回だけ呼び出されたい場合は、通知による別の解決策を次に示します。

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

- (void) doSomeStuff
{}

次にどこかに投稿する:

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