解除分配UIView子类实例时,ios App崩溃

时间:2013-08-23 08:18:39

标签: ios objective-c memory-management uiview gesture

在解除分配UIView子类实例时,我的应用程序本身构建了CocoaTouch和ARC崩溃。

这是崩溃日志。

OS Version:      iOS 6.1.3 (10B329)

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000008
Crashed Thread:  0

0: 0x39de65b0 libobjc.A.dylib objc_msgSend + 16
1: 0x31edb694 CoreFoundation -[NSArray makeObjectsPerformSelector:] + 300
2: 0x33d8c57a UIKit -[UIView(UIViewGestures) removeAllGestureRecognizers] + 146
3: 0x33d8c144 UIKit -[UIView dealloc] + 440
4: 0x00240b36 MyApp -[StandardPanelView .cxx_destruct](self=0x20acba30, _cmd=0x00240985) + 434 at StandardPanelView.m:139
5: 0x39deaf3c libobjc.A.dylib object_cxxDestructFromClass(objc_object*, objc_class*) + 56
6: 0x39de80d2 libobjc.A.dylib objc_destructInstance + 34
7: 0x39de83a6 libobjc.A.dylib object_dispose + 14
8: 0x33d8c26a UIKit -[UIView dealloc] + 734
9: 0x0022aa14 MyApp -[StandardPanelView dealloc](self=0x20acba30, _cmd=0x379f1a66) + 156 at StandardPanelView.m:205
10: 0x39de8488 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 168
11: 0x31e98440 CoreFoundation _CFAutoreleasePoolPop + 16
12: 0x31f28f40 CoreFoundation __CFRunLoopRun + 1296
13: 0x31e9bebc CoreFoundation CFRunLoopRunSpecific + 356
14: 0x31e9bd48 CoreFoundation CFRunLoopRunInMode + 104
15: 0x35a502ea GraphicsServices GSEventRunModal + 74
16: 0x33db1300 UIKit UIApplicationMain + 1120
17: 0x00113c50 MyApp main(argc=1, argv=0x2fd3ed30) + 140 at main.m:23

问题是:

  1. 可能设置错误导致[UIView(UIViewGestures)removeAllGestureRecognizers]的内部调用崩溃。一种理论是手势阵列中的某些手势已经在其他地方解除分配。
  2. 当UIView包含子视图时,重新分配过程的顺序如何?
  3. 一些额外的背景信息:

    1. 发生了崩溃,但没有确切的方法来重现它。
    2. StandardPanelView实例作为手势的委托,属于其子视图。
    3. 我们在StandardPanelView实例上使用flyweight,即缓存和回收。
    4. 提前感谢任何有关崩溃可能发生的提示。

1 个答案:

答案 0 :(得分:1)

我的第一印象是您可能正在尝试访问刚刚取消分配的StandardPanelView。

  
      
  • 可能设置错误导致[UIView(UIViewGestures)removeAllGestureRecognizers]的内部调用崩溃。一种理论是手势阵列中的某些手势已经在其他地方解除分配。
  •   

这不是因为UIGestureRecognizer被解除分配。 UIView强烈持有NSArray中的UIGestureRecognizers。当它们仍在阵列中时,它们不会被释放。

但是,UIGestureRecognizer的委托可能已被取消分配。这只是一个(assign)属性,意味着它不是强保持的,如果委托被释放,它将是一个悬空指针。因此,如果在[NSArray makeObjectsPerformSelector:]中使用委托,则可能会发生这种情况。

  
      
  • 当UIView包含子视图时,重新分配过程的顺序如何?
  •   

对象从'parent'释放到'child',即。超级视图被释放,然后是子视图,然后是手势识别器。 (尽管在手势识别器是实现细节之前是否释放了子视图,因此您可能不应该依赖它)。

我们可以在一个简单的样本控制器中看到这一点:

// The UIView that will be used as the main view
// This is the superview
@interface MyView : UIView
@end

@implementation MyView
- (void)dealloc {
    NSLog(@"Dealloc MyView");
}
@end


// This view will be put inside MyView to be used as a subview
@interface MySubview : UIView
@end

@implementation MySubview
- (void)dealloc {
    NSLog(@"Dealloc MySubview");
}
@end


// This is the gesture recognizer that we will use
// We will give one to each view, and see when it is deallocated
@interface MyGestureRecognizer : UIGestureRecognizer
@property (nonatomic, copy) NSString *tag;
@end

@implementation MyGestureRecognizer
@synthesize tag;
-(void)dealloc {
    NSLog(@"Dealloc MyGestureRecognizer tag: %@", tag);
}
@end


// Just a test view controller that we will push on/pop off the screen to take a look at the deallocations
@interface TestViewController : UIViewController 
@end

@implementation TestViewController
- (void)loadView {
    self.view = [[MyView alloc] init];
    MyGestureRecognizer *recognizer = [[MyGestureRecognizer alloc] initWithTarget:self action:@selector(doStuff)];
    recognizer.tag = @"MyViewGestureRecognizer";
    recognizer.delegate = self;
    [self.view addGestureRecognizer:recognizer];

}

- (void)viewDidLoad {
    [super viewDidLoad];

    MySubview *subview = [[MySubview alloc] init];
    MyGestureRecognizer *recognizer = [[MyGestureRecognizer alloc] initWithTarget:self action:@selector(doStuff)];
    recognizer.tag = @"MySubviewGestureRecognizer";
    recognizer.delegate = self;
    [subview addGestureRecognizer:recognizer];
    [self.view addSubview:subview];
}

- (void)doStuff {
  // we don't actually care what it does
}
@end

我们所做的只是将MyView添加为TestViewController的主视图,然后在MyView中添加MySubview。我们还为每个视图附加了MyGestureRecognizer。

当我们将它从屏幕上移开时,我们的日志输出显示:

Dealloc TestViewController
Dealloc MyView
Dealloc MySubview
Dealloc MyGestureRecognizer tag: MySubviewGestureRecognizer
Dealloc MyGestureRecognizer tag: MyViewGestureRecognizer

很抱歉答案很长......自你发布以来已经有3个月了,所以也许你已经解决了这个问题,但是如果有其他人偶然发现这个问题,我希望它有所帮助。