Переключение просмотров EXC_BAD_ACCESS - PullRequest
2 голосов
/ 03 июня 2011

У меня есть UIView в моем классе (кроме исходного представления), созданный в конструкторе интерфейсов.

@interface TimeLineGrid : UIViewController {

UIView *toggleView;

}

@property (nonatomic, retain) IBOutlet UIView *toggleView;

Я тоже это синтезировал. Я реализовал жест смахивания, так что при смахивании вид с переключателем добавляется, а при смахивании вид с переключателем удаляется.

-(void)swipedUp {

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:2.0f];

    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];

    [self.view addSubview:self.toggleView];

    [UIView commitAnimations];



}

-(void)swipedDown {

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:2.0f];

    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];

    [self.toggleView removeFromSuperview];

    [UIView commitAnimations];

}

Работает нормально, когда я провожу один раз и после этого провожу вниз. Но когда я провожу еще раз, он вылетает с ошибкой EXC_BAD_ACCESS. Я знаю, что это как-то связано с увеличением числа сохранений при добавлении Subview и уменьшением при удалении Subview. Может кто-то пролить больше света на это? Как мне добиться этого переключения?

EDIT: Моя иерархия представлений выглядит следующим образом:

->UIView (toggleView)
->UIView (mainView to which toggleView is being added)
 -->UIToolBar

Ответы [ 4 ]

3 голосов
/ 12 июня 2011

Скорее всего, представление освобождается при вызове [self.toggleView removeFromSuperview];. Я рекомендую немного реструктурировать свой код.

Поскольку вы создаете представление в IB, объявите его в заголовочном файле как

IBOutlet UIView *toggleView;

Не не включает вызов свойства или синтез. Поскольку вы не устанавливаете или не получаете toggleView, просто обратитесь к нему по указателю.

В реализации установите указатель на nil в viewDidUnload и отпустите его в dealloc. Затем настройте методы переключения следующим образом:

-(void)swipedUp {
    if (![toggleView superview]) {

        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:2.0f];

        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];

        [self.view addSubview:toggleView];

        [UIView commitAnimations];
    }
}

-(void)swipedDown {

    if ([toggleView superview]) {

        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:2.0f];

        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];

        [toggleView removeFromSuperview];

        [UIView commitAnimations];
    }
}

Здесь предложение if отлавливает событие, когда пользователь дважды проводит пальцем вверх, и не отвечает на второй удар. Также обратите внимание, что вместо self.toggleView.

используется toggleView.

Это должно решить проблему.

3 голосов
/ 06 июня 2011

Не могли бы вы применить такие изменения и сказать, в каком именно UIView возникли проблемы?

  1. Открыть XCode / Product / Edit Scheme ...
  2. Перейдите в Переменные среды и нажмите плюс, чтобы добавить переменную
  3. Добавить переменную NSZombieEnables - значение: ДА
  4. Добавить переменную MallocStackLoggingNoCompact - значение: 1

После запуска приложения вы увидите, какой именно объект был удален, при его вызове.

1 голос
/ 12 июня 2011

Я сделал приложение, содержащее UITabbar, и у меня такое же поведение, но с UIButton.

Это происходит, когда вы не отпускаете объект, для которого вы вызываете removeFromSuperview, у меня тот же эффект, когда я удалял UIButton из моего представления viewControllers.

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

Но если я изменю вкладку, то вернусь к моему контроллеру представления, где кнопка ранее отображалась после удаления ее из вида, тогда она исчезла.

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

Какие у вас варианты: -

  1. Вы можете вызвать removeFromSuperview для uiview или его объектов подкласса и вызвать release для него или сделать его нулевым.

  2. Вы можете скрывать или отображать эти объекты, используя свойство hidden вместо удаления их из суперпредставления.

  3. (я не пробовал это точно) Вы можете создать объект UIView в реализации вашего класса, а затем добавить его как subview и затем присвоить его переменной вашего экземпляра вашего класса с помощью оператора точки и затем отпустите ранее созданный объект UIView.

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

1 голос
/ 09 июня 2011

Я предлагаю сделать представления, которые вы хотите показать / скрыть, быть обоими подпредставлениями представления контейнера.Затем в своем анимационном блоке вы сначала удаляете исчезающий вид и добавляете вид, который хотите показать.Например:

@interface TimeLineGrid : UIViewController {
    // declare the views you want to flip between
    UIView *mainView;
    UIView *toggleView;
}

@property (nonatomic, retain) IBOutlet UIView *mainView;
@property (nonatomic, retain) IBOutlet UIView *toggleView;

В вашей реализации:

// self.view is the container view (an instance of UIView).
// Initially, self.mainView is a subview of self.view

-(void)transitionFromView:(UIView *)fromView toView:(UIView *)toView withAnimation:(UIViewAnimationTransition)animation {

    if ([toView superview]) {
        // toView already shown
        return;
    }

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:2.0f];

    [UIView setAnimationTransition:animation forView:self.view cache:NO];

    [self.view removeFromSuperview:fromView];
    [self.view addSubview:toView];

    [UIView commitAnimations];

}

-(void)swipedUp {
    [self transitionFromView:self.mainView 
                      toView:self.toggleView 
               withAnimation:UIViewAnimationTransitionFlipFromLeft];
}

-(void)swipedDown {
    [self transitionFromView:self.toggleView 
                      toView:self.mainView 
               withAnimation:UIViewAnimationTransitionFlipFromRight];
}

Обратите внимание, однако, что использование метода setAnimationTransition:forView:cache: теперь не рекомендуется.Apple рекомендует использовать метод UIView transitionWithView:duration:options:animations:completion: (см. Ссылку UIView ).

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...