Ios app crashing when freeing instance of subclass of UIView

My application, originally built with CocoaTouch and ARC errors when freeing an instance of a UIView subclass.

Here is the crash log.

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 

Questions:

  • which can be set incorrectly, which causes the failure of the internal call [UIViewGestures) removeAllGestureRecognizers]. One of the theories is that some kind of gesture in an array of gestures is freed up somewhere else.
  • When a UIView contains subviews, how does the process of the release process go?

Additional additional information:

  • An accident occurs, but there is no exact way to reproduce it.
  • The StandardPanelView instance acts as a delegate for gestures that applies to its views.
  • We use flies in instances of StandardPanelView, i.e. caching and reuse.

Thanks in advance for any hint on how this failure might occur.

+4
source share
1 answer

My first impression is that you can try to access the StandardPanelView standard that has just been released.

  • What could be wrong, which leads to the failure of the internal call [UIViewGestures) removeAllGestureRecognizers]. One of the theories is that some kind of gesture in an array of gestures is freed up somewhere else.

This will not happen because the UIGestureRecognizer has been released. UIView strongly contains UIGestureRecognizers in NSArray. They will not be freed while they are still in the array.

However, the UIGestureRecognizer delegate may have received an exemption. This is only a property (assign), which means that it is not strongly held, and if the delegate is released, it will be a dangling pointer. So, if a delegate is used in [NSArray makeObjectsPerformSelector:] , this can happen.

  • When a UIView contains subviews, how does the process of the release process go?

Objects are exempted from 'parent' to 'child', i.e. the supervisor is released, then submits, then the gesture recognizers. (Although regardless of whether the sub-items are freed up, before gesture recognizers are implementation details, so you probably shouldn't depend on it).

We can see this in a simple sample controller:

  // 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

All we do is add MyView as the main view for TestViewController, and then add MySubview inside MyView. We also attach MyGestureRecognizer to each of the views.

When we push it from the screen, our output to the log:

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

Sorry for the long answer ... It has been about three months since you posted it, so maybe you have already solved the problem, but if someone else stumbles upon this answer, I hope this helps .

+1
source

Source: https://habr.com/ru/post/1498553/


All Articles