2015-02-08 74 views
0

我遇到了UIViews和手动内存管理的奇怪问题。removeFromSuperview导致崩溃(非ARC)

我有一个视图(contentView)这是视图控制器的主视图。

在长按contentView后,另一个视图应该淡入(在其上)。

手势结束时,附加视图淡出。

的问题是:

内容查看接收长按,我创建了辅助视图,将其添加到内容查看,然后松开,这是/是常见的做法回到ARC之前的日子里。

它可以在iPhone上正常工作,但它会在iPad上崩溃!

的crashy行是:

[ZPNowPlayingItemInfoView dealloc] 

...当我删除从内容查看辅助视图,其被触发。

为什么会发生这种情况的任何线索?

如果我注释掉释放线(见我的代码注释),它完美的作品在两台设备上,但它感觉不好

下面的代码:

-(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]; 

    }]; 

} 

附:我需要使用手动内存管理。这是对越狱设备的调整。

堆栈跟踪:

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 release];'应该被取消注释。只看代码,我担心'[infoView setAlpha:0.f];'后面跟着'[contentView addSubview:infoView];'。我一直有''''alpha'的奇怪 - 例如,如果您使用'0.1'的初始'alpha'会发生什么情况。我想知道是否添加'subview'与'alpha'为'0'实际上增加了保留计数? – 2015-02-08 21:06:37

+0

@RoboticCat我试着改变阿尔法。它仍然崩溃:(我已经添加了堆栈跟踪到这个问题 – 2015-02-08 21:23:23

+0

我认为你将不得不切换到IB,并使用旧的方法来追踪使用NSZombies的内存问题:https:// developer .apple.com /库/ IOS /文档/ DeveloperTools /概念/ InstrumentsUserGuide/MemoryManagementforYourApp/MemoryManagementforYourApp.html#// apple_ref/DOC/UID/TP40004652-CH11-SW8 – 2015-02-08 21:29:09

回答

2

你有ZPNowPlayingItemInfoView类中的一些问题。当这个问题发生时?只有当对象被释放时。当你发表评论[infoView release]时,你的对象永远不会被释放,问题也不会出现 - 尽管如此,你仍然会有内存泄漏。

检查什么ZPNowPlayingItemInfoView呢,特别是其dealloc方法。你确定你正在构建它吗? item总是一个有效的对象吗?

看到ZPNowPlayingItemInfoView dealloc方法后,问题很明显 - [super dealloc]必须始终是最后一次调用,而不是第一次调用。一旦你释放了对象,访问它的属性是一个未定义的操作。

+0

我已将接口和dealloc方法添加到问题 – 2015-02-08 22:00:43

+0

@MatteoPacini编辑答案。 – Sulthan 2015-02-08 22:03:44

+0

这是正确的答案!发送消息'dealloc'作为最后的操作可以解决问题。非常感谢! – 2015-02-09 00:05:54

0

在评论release是一种可行的解决方法时,表明您已经经常发布一次。它可能是您发布的最新版本。

removeFromSuperview确实由1

降低保留计数我建议再逛视图对象的整个生命周期。这可能会很棘手。每个保留需要具有恰好一个对应的版本或自动释放。使用其吸气器(self.myView = subview)将视图分配给属性确实会保留该视图,并将其他视图重新分配给该属性(self.myView = someOhterview)版本subview。 与此相反,直接访问iVar(myView = subview)不会维护发布/保留周期。 还有更多。添加视图并将其从数组中移除,set或dictionary将相应地更改保留计数。

所以,去拥有它更深入的了解。使用仪器观察保留计数。