How to debug ARC by deleting an object if it shouldn't

I have a case in my iOS game (compiled with ARC) where an object (ivar, NSMutableDictionary) is removed in the Release build when it clearly shouldn't be. The Debug build is fine.

I am trying to find the best way to debug this. If I put any checks against the object, it hangs like it should. I know the object is being used because the application crashes, so the objects are being accessed.

I used Zombie objects to communicate that an object is being removed, but I don't know where or when this is happening.

Is there a way to see when the compiler thinks these objects are no longer needed or when they are actually deleted (which might not tell me anything if it's in the autostart pool).

Does anyone have any good tips for tracking this down? I don’t want to just call it a compiler error, but I don’t see how the compiler would think that this object is no longer referenced as it is referenced all over the place. The object the ivar resides in is where all my code is executed, so it's clearly still around (and much worse if it wasn't).

For now, I'll just leave this line of code to debug, resulting in the object not being deleted, but I don't like shipping my application with this solution.

Thank.

+3


source to share


3 answers


The place to put the debug code is in the dealloc

object method . You can put a breakpoint here (even in Release mode) and see at what point it goes away.

The most likely reason is that some of the code is either reordered or dropped in Release.

When you say "it is referenced everywhere" do you mean that you have objects that refer to it in their properties? The first rule of memory management is to keep (put in ivar) what you need and free up what you no longer need. If you have objects that take care of this object, then they must have a strong property pointing to it. If they do, then it certainly won't go away.




Dangling strong pointers in ARC offer a serious problem in your code. I would start by looking wherever you use bridges ( __bridge

in particular). Make sure you are passing objects to void pointers incorrectly.

Watch out for the use of C arrays. If you go off the end of the C array, you might damage other memory, which can cause problems like this.

Likewise, watch for any use of anything that takes an argument length

, such as in NSString

and NSData

. If you pass a value too long, you can exit the end of the data and mess up other variables. Likewise with raw pointers through memory malloc

.

+1


source


We ran into a problem today that sounds the same as the one you are facing. We load the class using a custom method from the NSDictionary loaded from the plist file and our application now crashes at the end of this method due to double release. We found that turning off binary release optimizations was all we could do to fix this.

We haven't changed any related code to the method that now crashes (it works fine for about 2 months), and after many hours of trying to figure out where the problem is, we found that the only thing we can fix at the moment is to change. " optimization level to No for our release code. Switch to.

Project -> Objectives -> Binary Name -> Build Settings -> Optimization Level -> Release



And set it to "None -O0".

I can only assume that there is a very strange bug in the optimizer, but I hope this helps you!

+1


source


This happens to me too, but with weak IBOutlets.

@property (nonatomic, weak) IBOutlet UIView *blahView;


[self.blahView removeFromSuperview];
[self.otherView addSubview:self.blahView];

      

After the first line compiler thinks there are no more object references and does not issue / nilds.

Keeping a weak reference ivar and using a temporary variable (in scope) to do this convinces the compiler not to release it.

UIView *blahView = self.blahView;
[blahView removeFromSuperview];
[self.otherView addSubview:blahView];

      

Does your problem solve?

+1


source







All Articles