title: iOS: Sliding UIView on/off screen
body: <p>I'm working on an app where having a "drawer" on the left-hand side would be very beneficial. I'm doing some initial testing to see how I would best accomplish this, and I'm having some very basic trouble.</p>
  
  <p><b>My Setup</b><br />
  1. I am using a single-view application template in Xcode 4. <br />
  2. To the xib's "main/border" view, I've added 2 UIViews (LeftPanel and RightPanel) and a UIButton (ShowHideButton). <br />
  3. I've colored the LeftPanel green and the RightPanel blue for easier visibility. <br />
  4. When the view is loaded, both panels are visible and the UIButton has the text "Hide Panel". <br />
  5. Upon pressing the button, LeftPanel should slide off the screen (to the left) and RightPanel should expand to take up its original space plus the space vacated by LeftPanel. <br />
  6. At this point, ShowHideButton should change its text to "Show Panel". <br />
  7. Upon pressing the button again, LeftPanel should slide back onto the screen (from the left) and RightPanel should shrink to "give it back" its original space. <br />
  8. At this point, ShowHideButton should change its text back to "Hide Panel". <br /></p>
  
  <p>I'm implementing the animation using <code>animateWithDuration:animations:completion:</code>. So far, the transition <b>OFF</b> the screen is working fine (very well, actually). <br /><br />
  What's troubling me is that when I then try to bring LeftPanel "back", I'm getting an EXC_BAD_ACCESS. I've posted my code below, and I've looked at it, but I really can't see what I'm accessing that's been released (or whatever is causing the EXC_BAD_ACCESS). <br /> <br /></p>
  
  <pre><code>DrawerTestingViewController.h
  #import &lt;UIKit/UIKit.h&gt;
  
  typedef enum {
      kHidden,
      kShown
  } PanelState;
  
  @interface DrawerTestingViewController : UIViewController {
  
      PanelState   currentState;
  
      UIButton    *showHideButton;
  
      UIView      *leftPanel;
      UIView      *rightPanel;
  }
  
  @property (assign, nonatomic)          PanelState   CurrentState;
  
  @property (strong, nonatomic) IBOutlet UIButton     *ShowHideButton;
  
  @property (strong, nonatomic) IBOutlet UIView       *LeftPanel;
  @property (strong, nonatomic) IBOutlet UIView       *RightPanel;
  
  - (IBAction)showHidePressed:(id)sender;
  
  @end
  </code></pre>
  
  <p><br /></p>
  
  <pre><code>DrawerTestingViewController.m
  #import "DrawerTestingViewController.h"
  
  @implementation DrawerTestingViewController
  
  @synthesize CurrentState    = currentState;
  @synthesize LeftPanel       = leftPanel;
  @synthesize RightPanel      = rightPanel;
  @synthesize ShowHideButton  = showHideButton;
  
  #pragma mark - My Methods
  
  - (IBAction)showHidePressed:(id)sender
  {
      switch ([self CurrentState]) {
          case kShown:
              // Hide the panel and change the button's text
              // 1. Hide the panel
              [UIView animateWithDuration:0.5 
                  animations:^{
                  // b. Move left panel from (0, 0, w, h) to (-w, 0, w, h)
                  CGRect currLeftPanelRect = [[self LeftPanel] frame];
                  currLeftPanelRect.origin.x = -1 * currLeftPanelRect.size.width;
                  [[self LeftPanel] setFrame:currLeftPanelRect];
                  // c. Expand right panel from (x, 0, w, h) to (0, 0, w + x, h)
                  CGRect currRightPanelRect = [[self RightPanel] frame];
                  currRightPanelRect.origin.x = 0;
                  currRightPanelRect.size.width += currLeftPanelRect.size.width;
                  [[self RightPanel] setFrame:currRightPanelRect];}
                  completion:NULL];
              // 2. Change the button's text
              [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
              // 3. Flip [self CurrentState]
              [self setCurrentState:kHidden];
              break;
          case kHidden:
              // Show the panel and change the button's text
              // 1. Show the panel
              [UIView animateWithDuration:0.5 
                  animations:^{
                  // b. Move left panel from (-w, 0, w, h) to (0, 0, w, h)
                  CGRect currLeftPanelRect = [[self LeftPanel] frame];
                  currLeftPanelRect.origin.x = 0;
                  [[self LeftPanel] setFrame:currLeftPanelRect];
                  // c. Expand right panel from (0, 0, w, h) to (leftWidth, 0, w - leftWidth, h)
                  CGRect currRightPanelRect = [[self RightPanel] frame];
                  currRightPanelRect.origin.x = currLeftPanelRect.size.width;
                  currRightPanelRect.size.width -= currLeftPanelRect.size.width;
                  [[self RightPanel] setFrame:currRightPanelRect];}
                  completion:NULL];
              // 2. Change the button's text
              [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
              // 3. Flip [self CurrentState]
              [self setCurrentState:kShown];
              break;
          default:
              break;
      }
  }
  
  - (void)viewDidLoad
  {
      [super viewDidLoad];
      [self setCurrentState:kShown];
  }
  
  - (void)viewWillAppear:(BOOL)animated
  {
      [super viewWillAppear:animated];
      switch ([self CurrentState]) {
          case kShown:
              [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
              break;
          case kHidden:
              [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
              break;
          default:
              break;
      }
  }
  
  @end
  </code></pre>
  
  <p>Am I missing something super-basic? Can anybody help?</p>
  
  <p><b><i>Thanks!</i></b></p>
  
  <p><b>Edit:</b>
  I've tried 2 more things:<br />
  1. The problem seems to be related to bringing the off-screen view on-screen, as starting with LeftPanel off-screen gives me the same problem.<br />
  2. Stepping through the code reliably causes Xcode (4 Beta for Lion) to crash. Here are the details (same for every crash):</p>
  
  <p>ASSERTION FAILURE in /SourceCache/DVTFoundation/DVTFoundation-867/Framework/Classes/FilePaths/DVTFilePath.m:373
  Details:  empty string is not a valid path
  Object:   
  Method:   +_filePathForParent:fileSystemRepresentation:length:allowCreation:
  Thread:   {name = (null), num = 55}
  Hints:   None
  Backtrace:
    0  0x00000001068719a6 -[IDEAssertionHandler handleFailureInMethod:object:fileName:lineNumber:messageFormat:arguments:] (in IDEKit)
    1  0x0000000105f3e324 _DVTAssertionFailureHandler (in DVTFoundation)
    2  0x0000000105edd16f +[DVTFilePath _filePathForParent:fileSystemRepresentation:length:allowCreation:] (in DVTFoundation)
    3  0x0000000105edcd4d +[DVTFilePath _filePathForParent:pathString:] (in DVTFoundation)
    4  0x0000000105ede141 +[DVTFilePath filePathForPathString:] (in DVTFoundation)
    5  0x00000001064a8dde -[IDEIndex queryProviderForFile:highPriority:] (in IDEFoundation)
    6  0x000000010655193b -[IDEIndex(IDEIndexQueries) symbolsMatchingName:inContext:withCurrentFileContentDictionary:] (in IDEFoundation)
    7  0x000000010aca6166 __68-[IDESourceCodeEditor symbolsForExpression:inQueue:completionBlock:]_block_invoke_01561 (in IDESourceEditor)
    8  0x00007fff93fb490a _dispatch_call_block_and_release (in libdispatch.dylib)
    9  0x00007fff93fb615a _dispatch_queue_drain (in libdispatch.dylib)
   10  0x00007fff93fb5fb6 _dispatch_queue_invoke (in libdispatch.dylib)
   11  0x00007fff93fb57b0 _dispatch_worker_thread2 (in libdispatch.dylib)
   12  0x00007fff8bb5e3da _pthread_wqthread (in libsystem_c.dylib)
   13  0x00007fff8bb5fb85 start_wqthread (in libsystem_c.dylib)</p>
  
  <p><b>Update: Screen Shots</b><br />
  Panel Shown (startup state)
  <img src="https://i.stack.imgur.com/7UXd5.png" alt="Panel Shown"><br />
  Panel Hidden (successful transition after button press)
  <img src="https://i.stack.imgur.com/5RDtS.png" alt="Panel Hidden"><br />
  Error: Pressing button again causes failure
  <img src="https://i.stack.imgur.com/gtyhF.png" alt="Error"></p>
  
  <hr>