【问题标题】:ios App crashes when deallocating an UIView subclass instanceios App 在释放 UIView 子类实例时崩溃
【发布时间】:2013-08-23 08:18:38
【问题描述】:

当释放 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 包含子视图时,释放过程的顺序是怎样的?

一些额外的背景信息:

  1. 发生了崩溃,但没有确切的方法可以重现它。
  2. StandardPanelView 实例作为手势代表属于其子视图。
  3. 我们在 StandardPanelView 实例上使用享元,即缓存和回收。

提前感谢您提供有关此崩溃如何发生的任何提示。

【问题讨论】:

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


    【解决方案1】:

    我的第一印象是您可能正在尝试访问刚刚被释放的 StandardPanelView。

    • 可能是什么设置错误导致内部调用 [UIView(UIViewGestures) removeAllGestureRecognizers] 崩溃。一种理论是,手势数组中的某些手势已在其他地方释放。

    这不会是因为 UIGestureRecognizer 被释放了。 UIView 强烈地将 UIGestureRecognizers 保存在 NSArray 中。当它们仍在数组中时,它们不会被释放。

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

    • 当 UIView 包含子视图时,释放过程的顺序是怎样的?

    对象从“父”释放到“子”,即。超级视图被释放,然后是子视图,然后是手势识别器。 (尽管在手势识别器之前是否释放子视图是一个实现细节,所以你可能不应该依赖它)。

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

    // 将用作主视图的 UIView // 这是超级视图 @interface 我的视图:UIView @结尾 @implementation 我的视图 - (无效)dealloc { NSLog(@"Dealloc MyView"); } @结尾 // 这个视图将被放在 MyView 中用作子视图 @interface MySubview : UIView @结尾 @implementation MySubview - (无效)dealloc { NSLog(@"Dealloc MySubview"); } @结尾 // 这是我们将使用的手势识别器 // 我们将为每个视图分配一个,并查看它何时被释放 @interface MyGestureRecognizer : UIGestureRecognizer @property (nonatomic, copy) NSString *tag; @结尾 @implementation MyGestureRecognizer @synthesize 标签; -(无效)dealloc { NSLog(@"Dealloc MyGestureRecognizer 标签:%@", tag); } @结尾 // 只是一个测试视图控制器,我们将按下/弹出屏幕以查看释放 @interface TestViewController : UIViewController @结尾 @implementation TestViewController -(无效)加载视图{ self.view = [[MyView alloc] init]; MyGestureRecognizer *recognizer = [[MyGestureRecognizer alloc] initWithTarget:self action:@selector(doStuff)]; 识别器.tag = @"MyViewGestureRecognizer"; 识别器.delegate = self; [self.view addGestureRecognizer:recognizer]; } - (void)viewDidLoad { [超级视图DidLoad]; MySubview *subview = [[MySubview alloc] init]; MyGestureRecognizer *recognizer = [[MyGestureRecognizer alloc] initWithTarget:self action:@selector(doStuff)]; 识别器.tag = @"MySubviewGestureRecognizer"; 识别器.delegate = self; [子视图 addGestureRecognizer:recognizer]; [self.view addSubview:subview]; } -(无效)doStuff { // 我们实际上并不关心它做了什么 } @结尾

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

    当我们将它推离屏幕时,我们的日志输出呈现:

    Dealloc TestViewController Dealloc MyView Dealloc MySubview Dealloc MyGestureRecognizer 标签:MySubviewGestureRecognizer Dealloc MyGestureRecognizer 标签:MyViewGestureRecognizer

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      • 1970-01-01
      相关资源
      最近更新 更多