2015-02-08 4 views
0

У меня возникла странная проблема с UIViews и ручным управлением памятью.removeFromSuperview вызывает сбой (не-ARC)

У меня есть вид (contentView), который является основным видом контроллера.

После долгого нажатия на contentView, другой вид должен исчезать (поверх него).

Когда жест заканчивается, дополнительный вид исчезает.

Этот вопрос:

Когда contentView получает длинное нажатие, я создаю дополнительный вид, добавьте его в contentView, а затем отпустить его, что/был обычной практикой назад в дни до ARC.

Он работает нормально на iPhone, но он падает на iPad!

crashy линия:

[ZPNowPlayingItemInfoView dealloc] 

... который сработал, когда я удалить дополнительный вид из contentView.

Любые подсказки о том, почему это происходит?

Если я закомментируйте релиз линии (см мой комментарий в коде), она работает безупречно на обоих устройствах, но неможет.

Вот код:

-(void)longPressDetected:(UILongPressGestureRecognizer*)longPressGR 
{ 
    //Content view of the view controller I'm in 
    UIView *contentView = MSHookIvar<UIView*>(self, "_contentView"); 

    if (longPressGR.state == UIGestureRecognizerStateBegan) { 

    id item = MSHookIvar<MPAVItem*>(self, "_item"); 

    ZPNowPlayingItemInfoView *infoView = 
     [[ZPNowPlayingItemInfoView alloc] initWithFrame: 
      CGRectMake(0,0,contentView.frame.size.width,contentView.frame.size.height) 
       item:item]; 

    //infoView retain count: 1 

    [infoView setAlpha:0.f]; 
    [contentView addSubview:infoView]; 

    //infoView retain count: 3 (???) 

    //iPad goes berserk on this line 
    //Commented - Works both on iPhone and iPad 
    //Uncommented - Works only on iPhone 
    //[infoView release]; 

    //infoView retain count: 2 (if release is uncommented) 

    [UIView animateWithDuration:0.35f animations:^{ 

     [infoView setAlpha:1.0f]; 

    } completion:^(BOOL finished) { 

     //infoView retain count: 3 

    }]; 

    } else if (longPressGR.state == UIGestureRecognizerStateEnded) { 

    ZPNowPlayingItemInfoView* infoView = nil; 

    for (UIView *subview in contentView.subviews) { 

     if ([subview isKindOfClass:[ZPNowPlayingItemInfoView class]]) { 

      infoView = (ZPNowPlayingItemInfoView*)subview; 
      break; 

     } 

    } 

    [UIView animateWithDuration:0.35f animations:^{ 

     [infoView setAlpha:0.f]; 

    } completion: ^(BOOL finished){ 

     [infoView removeFromSuperview]; 

    }]; 

} 

P.S. Мне нужно использовать ручное управление памятью. Это настройка для джейлбрейк-устройств.

Стек след:

Thread 0 name: Dispatch queue: com.apple.main-thread 
Thread 0 Crashed: 
0  libobjc.A.dylib     0x195287bdc 0x19526c000 + 0x1bbdc // objc_msgSend + 0x1c 
1  + Musix.dylib      0x10015b19c 0x100154000 + 0x719c // -[ZPNowPlayingItemInfoView dealloc] + 0x48 
2  libsystem_blocks.dylib   0x19590d90c 0x19590c000 + 0x190c // _Block_release + 0xfc 
3  UIKit       0x188ef8590 0x188eb0000 + 0x48590 // -[UIViewAnimationBlockDelegate dealloc] + 0x44 
4  CoreFoundation     0x1845f1374 0x1845ec000 + 0x5374 // CFRelease + 0x208 
5  CoreFoundation     0x184601004 0x1845ec000 + 0x15004 // -[__NSDictionaryI dealloc] + 0x8c 
6  libobjc.A.dylib     0x19528d720 0x19526c000 + 0x21720 // (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 0x230 
7  CoreFoundation     0x1845f4f90 0x1845ec000 + 0x8f90 // _CFAutoreleasePoolPop + 0x18 
8  CoreFoundation     0x1846c774c 0x1845ec000 + 0xdb74c // __CFRunLoopRun + 0x5d8 
9  CoreFoundation     0x1845f51f0 0x1845ec000 + 0x91f0 // CFRunLoopRunSpecific + 0x188 
10  GraphicsServices    0x18d7575a0 0x18d74c000 + 0xb5a0 // GSEventRunModal + 0xa4 
11  UIKit       0x188f26780 0x188eb0000 + 0x76780 // UIApplicationMain + 0x5cc 
12  Music (*)      0x10006ee28 0x100064000 + 0xae28 // 0x0000adac + 0x7c 
13  libdyld.dylib     0x1958e2a04 0x1958e0000 + 0x2a04 // start + 0x0 

ZPNowPlayingItemInfoView:

@interface ZPNowPlayingItemInfoView() 

@property (nonatomic, retain) MPAVItem* item; 

@property (nonatomic, retain) MPUSlantedTextPlaceholderArtworkView *artworkView; 
@property (nonatomic, retain) UILabel *artistLabel; 
@property (nonatomic, retain) UILabel *albumLabel; 
@property (nonatomic, retain) UILabel *songLabel; 

@end 

ZPNowPlayingItemInfoView dealloc:

-(void)dealloc 
{ 
    [super dealloc]; 

    [self.item release]; 

    [self.artworkView release]; 
    [self.artistLabel release]; 
    [self.songLabel release]; 
} 
+1

Хммм .... похоже, долгое время с момента прибытия ARC. По-моему, '' выпуск [infoView]; 'должен быть раскоментирован. Просто глядя на код, я беспокоюсь о '[infoView setAlpha: 0.f];', а затем '[contentView addSubview: infoView];'. У меня всегда были странности с 'alpha''s' 0' - что происходит, если вы используете, например, начальную букву 'alpha'. Интересно, добавляет ли 'subview' с' alpha' из '0', фактически увеличивает счетчик удержания? –

+0

@RoboticCat Я пробовал менять альфу. Он по-прежнему падает :(Я добавил трассировку стека к вопросу. –

+0

Я думаю, вам придется переключиться на IB и использовать старые методы для отслеживания проблем с памятью с помощью 'NSZombies': https: // developer .apple.com/library/ios/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/MemoryManagementforYourApp/MemoryManagementforYourApp.html # // apple_ref/doc/uid/TP40004652-CH11-SW8 –

ответ

2

У вас есть проблема в классе ZPNowPlayingItemInfoView. Когда эта проблема возникает? Только когда объект освобождается. Когда вы прокомментируете [infoView release], ваш объект никогда не освобождается, и проблема не возникает - у вас будет утечка памяти.

Осмотрите, что ZPNowPlayingItemInfoView делает, особенно его dealloc метод. Вы уверены, что строите его правильно? Является ли item всегда действительным объектом?

После просмотра метода ZPNowPlayingItemInfoView dealloc проблема довольно ясна - [super dealloc] всегда должен быть последним, а не первым. После того как вы освободили объект, доступ к его свойствам является неопределенной операцией.

+0

Я добавил интерфейс и метод dealloc к вопросу –

+0

@MatteoPacini отредактировал ответ. – Sulthan

+0

Правильный ответ! Отправка сообщения 'dealloc' в качестве последней операции устраняет проблему. Спасибо огромное! –

0

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

removeFromSuperview действительно уменьшает количество сохранения на 1.

Я предлагаю вновь посетить полный жизненный цикл объекта вида. Это может быть сложно. Каждое сохранение должно иметь ровно один соответствующий релиз или автореферат.Присвоение вида объекту с использованием его получателя (self.myView = subview) сохраняет его и переназначает другое представление свойства (self.myView = someOhterview) выпуска subview. Напротив, прямой доступ к iVar (myView = subview) не поддерживает цикл выпуска/сохранения. Существует больше, чем это. Добавление представления и удаление его из массива, установка или словарь соответственно изменят счетчик удержания.

Так что иди и посмотри на него глубже. Используйте инструменты для наблюдения за удержанием счета.

Смежные вопросы