title: Changing a frame in viewDidLayoutSubviews
body: <p>When a view controller's view is first shown I want to run an animation in which all elements in the view controller slide from outside the bottom of the screen to their natural positions. To achieve this, I do <code>subview.frame.origin.y += self.view.frame.size.height</code> in <code>viewDidLayoutSubviews</code>. I also tried <code>viewWillAppear</code>, but it doesn't work at all. Then I animate them up to their natural positions with <code>subview.frame.origin.y -= self.view.frame.size.height</code> in <code>viewDidAppear</code>.</p>
  
  <p>The problem is that <code>viewDidLayoutSubviews</code> is called several times throughout the view controller's lifespan. As such, when things like showing the keyboard happen all my content gets replaced outside the view again.</p>
  
  <p>Is there a better method for doing this? Do I need to add some sort of flag to check whether the animation has already run?</p>
  
  <p>EDIT: here's the code. Here I'm calling <code>prepareAppearance</code> in <code>viewDidLayoutSubviews</code>, which works, but <code>viewDidLayoutSubviews</code> is called multiple times throughout the controller's life span.</p>
  
  <pre><code>- (void)viewDidLayoutSubviews
  {
      [super viewDidLayoutSubviews];
      [self prepareAppearance];
  }
  
  - (void)viewDidAppear:(BOOL)animated
  {
      [super viewDidAppear:animated];
      [self animateAppearance];
  }
  
  
  - (NSArray *)animatableViews
  {
      return @[self.createAccountButton, self.facebookButton, self.linkedInButton, self.loginButton];
  }
  
  - (void)prepareAppearance
  {
      NSArray * views = [self animatableViews];
      NSUInteger count = [views count];
  
      for (NSUInteger it=0 ; it &lt; count ; ++it) {
  
          UIView * view = [views objectAtIndex:it];
          CGRect frame = view.frame;
  
          // Move the views outside the screen, to the bottom
          frame.origin.y += self.view.frame.size.height;
  
          [view setFrame:frame];
      }
  }
  
  - (void)animateAppearance
  {
      NSArray * views = [self animatableViews];
      NSUInteger count = [views count];
  
      for (NSUInteger it=0 ; it &lt; count ; ++it) {
  
          __weak UIView * weakView = [views objectAtIndex:it];
          CGRect referenceFrame = self.view.frame;
  
          [UIView animateWithDuration:0.4f
                                delay:0.05f * it
                              options:UIViewAnimationOptionCurveEaseOut
                           animations:^{
  
                               CGRect frame = weakView.frame;
                               frame.origin.y -= referenceFrame.size.height;
  
                               [weakView setFrame:frame];
                           }
                           completion:^(BOOL finished) {
                           }];
      }
  }
  </code></pre>