Подтвердить что ты не робот

IOS: раздвижной экран включения/выключения UIView

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

Моя установка
1. Я использую шаблон приложения одного вида в Xcode 4.
2. Для представления "main/border" xib я добавил 2 UIViews (LeftPanel и RightPanel) и UIButton (ShowHideButton).

3. Я окрашивал зеленый цвет LeftPanel и синий цвет RightPanel для большей видимости.

4. Когда изображение загружено, обе панели видны, а UIButton имеет текст "Скрыть панель".

5. При нажатии кнопки LeftPanel должен сдвигаться с экрана (влево), а RightPanel должен расширяться, чтобы занять исходное пространство плюс пространство, освобожденное LeftPanel.

6. На данный момент ShowHideButton должен изменить свой текст на "Показать панель".

7. При повторном нажатии кнопки LeftPanel должен вернуться на экран (слева), а RightPanel должен сжиматься, чтобы "вернуть" его исходное пространство.

8. На данный момент ShowHideButton должен изменить свой текст на "Скрыть панель".

Я реализую анимацию с помощью animateWithDuration:animations:completion:. Пока переход OFF работает нормально (очень хорошо, на самом деле).

Меня беспокоит то, что когда я пытаюсь вернуть LeftPanel "назад", я получаю EXC_BAD_ACCESS. Я разместил свой код ниже, и я посмотрел на него, но я действительно не вижу, к чему я обращаюсь, который был выпущен (или что-то другое вызывает EXC_BAD_ACCESS).

DrawerTestingViewController.h
#import <UIKit/UIKit.h>

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


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 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 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 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 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

Я пропустил что-то супер-основное? Может ли кто-нибудь помочь?

Спасибо!

Edit: Я пробовал еще 2 вещи:
1. Проблема, по-видимому, связана с отображением экранного представления на экране, поскольку запуск с экрана LeftPanel дает мне ту же проблему.
2. Выполнение кода надежно приводит к сбою Xcode (4 Beta for Lion). Вот подробности (одинаковые для каждого сбоя):

НЕИСПРАВНОСТЬ НЕИСПРАВНОСТИ в /SourceCache/DVTFoundation/DVTFoundation -867/Framework/Classes/FilePaths/DVTFilePath.m:373 Подробности: пустая строка не является допустимым путем. Объект: Метод: + _filePathForParent: fileSystemRepresentation: length: allowCreation: Тема: {name = (null), num = 55} Подсказки: Нет Backtrace: 0 000000001068719a6 - [IDEAssertionHandler handleFailureInMethod: object: fileName: lineNumber: messageFormat: arguments:] (в IDEKit) 1 0x0000000105f3e324 _DVTAssertionFailureHandler (в DVTFoundation) 2 0x0000000105edd16f + [DVTFilePath _filePathForParent: fileSystemRepresentation: length: allowCreation:] (в DVTFoundation) 3 0x0000000105edcd4d + [DVTFilePath _filePathForParent: pathString:] (в DVTFoundation) 4 0x0000000105ede141 + [DVTFilePath filePathForPathString:] (в DVTFoundation) 5 0x00000001064a8dde - [IDEIndex queryProviderForFile: highPriority:] (в IDEFoundation) 6 0x000000010655193b - [IDEIndex (IDEIndexQueries) символыMatchingName: inContext: withCurrentFileContentDictionary:] (в IDEFoundation) 7 0x000000010aca6166 __68- [IDESourceCodeEditor symbolForExpression: inQueue: completeBlock:] _ block_invoke_01561 (в IDESourceEditor) 8 0x00007fff93fb490a _dispatch_call_block_and_release (в libdispatch.dylib) 9 0x00007fff93fb615a _dispatch_queue_drain (в libdispatch.dylib)  10 0x00007fff93fb5fb6 _dispatch_queue_invoke (в libdispatch.dylib)  11 0x00007fff93fb57b0 _dispatch_worker_thread2 (в libdispatch.dylib)  12 0x00007fff8bb5e3da _pthread_wqthread (в libsystem_c.dylib)  13 0x00007fff8bb5fb85 start_wqthread (в libsystem_c.dylib)

Обновление: снимки экрана
Отображена панель (состояние запуска) Panel Shown
Панель скрыта (успешный переход после нажатия кнопки) Panel Hidden
Ошибка: нажатие кнопки снова вызывает сбой Error


4b9b3361

Ответ 1

После того, как я сыграл с этой связкой и ударился головой о стену, я, наконец, пришел к выводу, что мой код не был прав, если я не понял что-то о блоках. Выполнение моего кода при отладке дало ответы точно так, как я ожидал, но между окончанием блока анимации и началом блока завершения продолжалось выскакивание EXC_BAD_ACCESS.

Во всяком случае, я не уверен, откуда у меня возникла эта идея, но я подумал, что, возможно, захочу попытаться выполнить математические вычисления (для изменения кадров) вне моего блока анимации.

Угадайте, что? ЭТО РАБОТАЕТ!

Итак, без лишнего шума, вот рабочий код для того, что я хотел:

- (IBAction)showHidePressed:(id)sender
{
    switch ([self CurrentState]) {
        case kShown:
        {
            // Hide the panel and change the button text
            CGRect currLeftPanelRect = [[self LeftPanel] frame];
            currLeftPanelRect.origin.x -= currLeftPanelRect.size.width / 2;
            CGRect currRightPanelRect = [[self RightPanel] frame];
            currRightPanelRect.origin.x = 0;
            currRightPanelRect.size.width += currLeftPanelRect.size.width;
            // 1. Hide the panel
            [UIView animateWithDuration:0.5 
              animations:^{
              // b. Move left panel from (0, 0, w, h) to (-w, 0, w, h)
              [[self LeftPanel] setFrame:currLeftPanelRect];
              // c. Expand right panel from (x, 0, w, h) to (0, 0, w + x, h)
              [[self RightPanel] setFrame:currRightPanelRect];
              }
              completion:^(BOOL finished){ if(finished) {
              [[self ShowHideButton] setTitle:@"Show Panel" forState:UIControlStateNormal];
              [self setCurrentState:kHidden];
              }
              }];
        }            
            break;
        case kHidden:
        {
            // Show the panel and change the button 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 += currLeftPanelRect.size.width / 2;
              [[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:^(BOOL finished){ if(finished) {
              [[self ShowHideButton] setTitle:@"Hide Panel" forState:UIControlStateNormal];
              [self setCurrentState:kShown];
              }
              }];
        }
            break;
        default:
            break;
    }
}

Ответ 2

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