respondsToSelector send to deallocated object

谁说胖子不能爱 提交于 2019-12-04 09:33:43

Zombie is disabled as you use it with Memory Leaks since all Zombies would be signaled as leaks. To run the Zombie tool you can go to the Instrument menu and do File>New and chose the Zombie tool alone, doing so the program will stop if a zombie has received a message and you'll be given a link in a small pop up to that zombie object and its history

Somewhere you're allocating the XMLParser. Let's see that code. You're not auto-releasing it, are you?

Somewhere it's getting released... is it assigned to a property? Let's see that property definition.

Later on the respondsToSelector: method is being invoked, but that could be any method. The point is that your XMLParser got released before you intended.

In RootViewController.h I have declared the property rssParser:

@class XMLParser;

@interface RootViewController : UITableViewController {
    ...
    XMLParser *rssParser;
}
...
@property (retain, nonatomic) XMLParser *rssParser;

@end

In RootViewController.m I have a method called errorOccurred:

- (void)errorOccurred {
    [rssParser release];
    rssParser = nil;
    if ([activityIndicator isAnimating]) {
        [activityIndicator stopAnimating];
    }
}

In my XMLParser.m file I call the errorOccurred two times:

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    ...

    if ([_delegate respondsToSelector:@selector(errorOccurred)])
        [_delegate errorOccurred];
    else  
    {   
        [NSException raise:NSInternalInconsistencyException  
                    format:@"Delegate doesn't respond to errorOccurred:"];  
    }
}

To see how _delegate is declared, look at the tutorial http://www.cocoadevblog.com/iphone-tutorial-creating-a-rss-feed-reader. It is an id variable and has a own setter and getter method (you can also declare it as property I think). The second time:

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    ...

    if ([_delegate respondsToSelector:@selector(errorOccurred)])
        [_delegate errorOccurred];
    else  
    {   
        [NSException raise:NSInternalInconsistencyException  
                    format:@"Delegate doesn't respond to errorOccurred:"];  
    }
}  

The release of my rssParser variables are like the following:

In loadData in RootViewController.m I never release it. Unfortunately it will crash if I do it in loadData. It is only released if a error occurred (see above) or in the dealloc method. But I think that should work fine as it is declared as property.

- (void)loadData {
    if (newsItems == nil) {
        [activityIndicator startAnimating];  

        self.rssParser = [[XMLParser alloc] init];  
        [rssParser parseRssFeed:@"http://www.wrongurl.com/wrongrss.xml" withDelegate:self];  
    } else {  
        [self.tableView reloadData];  
    }  
}

In XMLParser.m I release it after the parse method:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {  
   ...

    NSXMLParser *rssParser = [[NSXMLParser alloc] initWithData:responseData];

    [rssParser setDelegate:self];

    [rssParser parse];

    [rssParser release];
    rssParser = nil;
}  

Note that the two variable names are the same (rssParser), but they are different. In RootViewController I'm creating an instance of XMLParser, and in XMLParser.m I'm creating an instance of NSXMLParser.

So I think I'll leave it at that, until I'm not experiencing a new error or someone of you explain me why this is bad.

Do you also have rssParser, the same instance variable you've set to release here...

- (void)errorOccurred {
    [rssParser release];
    rssParser = nil;
    if ([activityIndicator isAnimating]) {
        [activityIndicator stopAnimating];
    }
}

...released in your dealloc method? This would cause a double release and thus EXEC_BAD_ACCESS.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!