Действие UIButton не работает через некоторое время (вероятно, после сборки мусора)

У меня есть UIView с примерно 60 кнопками, которые вызывают один и тот же метод. При нажатии на кнопки я открываю разные изображения этим методом — я использую теги кнопок, чтобы знать, какая кнопка была вызвана и какое изображение отображать. Думайте об этом как о галерее.

Поскольку рисовать кнопки было сложно, я использовал для этого Interface Builder и создал XIB с этим UIView. Я просто перетаскивал кнопки в нужные места и подключал их к своему методу на событии TouchUpInside. Я использовал это, чтобы добавить вид к моему основному виду:

NSArray *xibContents = [[NSBundle mainBundle] loadNibNamed:@"Tour" owner:self options:nil];
UIView *tour = [xibContents lastObject];
[self.view addSubview:tour];

Пока все хорошо, на первый взгляд работает хорошо. К сожалению, есть некоторые проблемы, когда приложение используется в течение некоторого времени. Кнопки по-прежнему подсвечиваются (так что они все еще здесь!), но действие больше не вызывается. Там только подсветка, но никаких действий.

Я не знаю почему, но каким-то образом сборщик мусора, кажется, уничтожает цель UIButton. Почему? Как я могу это исправить?

Обратите внимание, что я не объявлял кнопки программно. Я думал, что разместить их в IB будет достаточно.

Также я не смог найти связи между предупреждениями о памяти и уничтожением целей UIButton. Предупреждения о памяти появляются в моем приложении, но в большинстве случаев кнопки все еще работают.

Но это должен быть сборщик мусора, потому что ошибка появляется совершенно случайно. Нет возможности воспроизвести эту ошибку, иногда это происходит после 5 кликов, иногда после 10 минут пребывания в моем приложении.


person andreas    schedule 01.08.2012    source источник
comment
Если вы используете ARC, сборка мусора отсутствует, а кнопки имеют сильную связь с текущим представлением. Если вы не используете ARC, то, вероятно, вы выпускаете объекты. То, что вы описали, не имеет с этим явных проблем; вам нужно добавить некоторые детали.   -  person Dustin    schedule 01.08.2012
comment
Извините, это немного сложно описать. Да, я использую ARC, я только что еще раз проверил свой проект, чтобы убедиться. Нет, я не выпускаю никаких своих объектов. Я заметил: когда я программно добавляю селектор, он продолжает работать. Так что проблема как-то в том, как все подключено к IB. Я действительно мог бы решить проблему программно, но это долгий путь для более чем 60 кнопок...   -  person andreas    schedule 01.08.2012
comment
Добавьте кнопки в массив, а затем добавьте селектор с циклом for.   -  person Dustin    schedule 01.08.2012
comment
Дастин: Был бы вариант, но мне нужно было бы подключить их вручную через IB, верно? Не очень элегантно, но, конечно, сработает. Или есть лучший вариант?   -  person andreas    schedule 01.08.2012


Ответы (3)


Это самый простой способ добавить селекторы ко всем вашим кнопкам.

for (UIView* view in self.view.subviews)
    if ([view isKindOfClass:[UIButton class]])
    {
         //Add selector
    }
person Dustin    schedule 01.08.2012

Вы можете попробовать загрузить перо следующим образом:

Сначала создайте свойство IBOutlet в своем заголовке. Затем, когда вы создаете Nib, подключите этот UIView IBOutlet к представлению верхнего уровня в Nib (тому, на котором все сидит). Затем в вашей реализации загрузите его следующим образом:

 [[NSBundle mainBundle] loadNibNamed:@"Tour" owner:self options:nil];
 // self.view if in a view controller
 [self addSubview:self.tourView]; 

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

и для отладки вы можете попробовать что-то вроде:

 for (UIView* view in self.view.subviews)
     if ([view isKindOfClass:[UIButton class]])
     {
               if([self.view respondsToSelector:@selector(myIBAction:)]){
                   NSLog(@"it still sees the method");
                }

         NSLog(@"Button Rect: .2%f, .2%f, .2%f, .2%f", view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
      }

как я упоминаю в комментариях

person Eric Welander    schedule 01.08.2012
comment
Я попробовал это только сейчас, но указатель все еще перестает работать случайным образом. Он работает при первой загрузке, как описано. Странный! - person andreas; 01.08.2012
comment
Вау, я бы сказал, что то, что только что упомянул @Dustin, является хорошей идеей с точки зрения отладки. Прокрутите подпредставления, но вместо добавления селектора посмотрите, появляется ли кнопка по-прежнему программно и есть ли к ней прикрепленный селектор. Еще одна полезная вещь для регистрации (с NSLog или точками останова) - это CGRect... тогда вы знаете, указывает ли указатель на фактический элемент интерфейса. - person Eric Welander; 01.08.2012
comment
В этом случае этот поиск подпредставления полезен только в том случае, если вы ищете его позже в жизни представления... возможно, с помощью [self PerformSelector:@selector(searchForButton) withObject:nil afterDelay:30] - person Eric Welander; 01.08.2012

Переустановка целей, когда что-то идет не так, означает, что нужно сделать что-то неправильное чуть громче или настойчивее.

Вы должны найти причину этой проблемы. Запустите инструменты (профиль сборки), выберите шаблон Allocations и запустите приложение. Запускайте, пока не возникнет проблема, затем остановите запись в «Инструментах», нажав красную кнопку записи в левом верхнем углу.

Выберите инструмент «Распределения» в списке слева, перейдите со «Статистика» на «Список объектов» на панели перехода, проходящей через окно чуть ниже временной шкалы. Теперь у вас есть строка для каждого объекта, который нужно выделить, сохранить, освободить и освободить. Щелкните маленькую стрелку, чтобы просмотреть историю для каждого объекта. (Строго говоря, это для каждого адреса памяти; многие объекты могут повторно использовать один и тот же адрес памяти во время выполнения приложения.) Вы также можете фильтровать что-либо в правом верхнем углу, развернуть правую боковую панель для полной трассировки стека для того, что выбрано и дважды щелкните запись для сопоставления с исходным кодом.

Об инструментах можно многое узнать; проверьте документацию и выполните поиск в Интернете. Но это определенно скажет вам, что происходит, так что вы сможете рассуждать о том, почему это происходит или чего не происходит.

person Jesper    schedule 01.08.2012