Debugging Help (message sent to a deallocated instance)

Discussion in 'Mac Programming' started by ArtOfWarfare, Oct 13, 2013.

  1. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #1
    I have a breakpoint set to stop on any exception, as well as "Zombie Objects" enabled.

    My program crashes when I click on a checkbox which uses Binding. It tells me that performSelector:withObject: is being called on an already deallocated instance of one of my class. The stack trace that it gives me isn't useful as it's entirely code that is already compiled that I didn't write that comes from Apple.

    Any suggestions on how to go about debugging this?
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    When a message is sent to a dealloc'ed object, the cause of the bug is in the past. Specifically, something over-released the object, or didn't retain it, so by the time the message is sent, the object in question is already dead.

    Think of Ebenezer Scrooge getting a message from Jacob Marley's ghost. Marley is already dead, and can't change what he does in his life. But Scrooge can change, only he has to do it before he dies.

    Start by working backwards in time from the message that's being sent to the dead object. What led to that? Then what messages were sent before that? And so on back through the lifetime of the object since it was alloc'ed. Be specific; debugging generalities is exceptionally difficult.

    The stack trace of the message to the dead object is only going to tell you a beyond-hope point in time. It's the point that the object is already dead, yet someone still thinks it's alive, and is sending it a message. Which means the object actually died (was released and dealloc'ed) before the errant message was sent. That's why you have to work backwards. That is, if the object is dead when sent the message foo, then something that happened before foo was sent is the culprit.
     
  3. ArtOfWarfare thread starter macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #3
    It seems to me that potentially the issue could be that the object shouldn't be getting called. But I get your point - I'll look for a release without a corresponding retain.
     
  4. ArtOfWarfare thread starter macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #4
    I've been busy with work for the past week but I finally had a moment to revisit this.

    I looked through all my code for places where I have release statements and I came across something suspicious looking:

    Code:
    - (id)init
        self = [super init];
        if (self) {
            [self startBrowsing];
            updateTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:@selector(collectData:) userInfo:null repeats:YES];
            [self autorelease];
        }
        return self;
    }
    Errr... what? Why is [self autorelease] in my init method? There's no corresponding retain or init... can it possibly be correct?
     
  5. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #5
    Without any other context, it seems unlikely to be correct.

    On general design principles, I can't think of a reason for an init method to change the ownership of itself. Unless something really special is happening, an object doesn't own itself: some other object does.

    Look here:
    https://developer.apple.com/library...a/Conceptual/MemoryMgmt/Articles/mmRules.html
    See the fourth rule.
     
  6. ArtOfWarfare thread starter macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #6
    Thinking about it a bit more - I suspect my code sample has both the source of the performSelector:withObject: call (in the form of that repeating timer) and the early release.
     

Share This Page