respondsToSelector 发送到已释放的对象

发布于 2024-09-16 06:04:04 字数 3852 浏览 0 评论 0 原文

如果我向 NSXML 解析器发送错误的 URL,我会尝试找出应用程序崩溃的原因(RSS 阅读器)。我收到了 EXC_BAD_ACCESS。所以经过一番搜索后我发现我必须使用僵尸。因此,我向环境添加了以下参数:

CFZombieLevel = 3
NSMallocStaclLogging = YES
NSDeallocateZombies = NO
MallocStackLoggingNoCompact = YES
NSZombieEnabled = YES
NSDebugEnabled = YES
NSAutoreleaseFreedObjectCheckEnabled = YES

我还添加了 malloc_error_break 作为断点。然后我在 GUI 中添加了一些其他断点并按下“构建”和“调试”。在控制台中,我收到以下消息:

2010-08-28 18:41:49.761 RssReader[2850:207] *** -[XMLParser respondsToSelector:]: message sent to deallocated instance 0x59708e0

有时我还收到以下消息: wait_fences:无法接收回复:10004003

如果我输入“shell malloc_history 2850 0x59708e0”,我会得到以下信息:

...
ALLOC 0x5970870-0x59709d7 [size=360]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -[UIApplication
...
----
FREE  0x5970870-0x59709d7 [size=360]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication
...
ALLOC 0x59708e0-0x597090f [size=48]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -[UIApplication 
... 
Binary Images:
    0x1000 -     0x6ff3 +RssReader ??? (???) <6EBB16BC-2BCE-CA3E-C76E-F0B078995E2D> /Users/svp/Library/Application Support/iPhone Simulator/4.0.1/Applications/AF4CE7CA-88B6-44D4-92A1-F634DE7B9072/RssReader.app/RssReader
    0xe000 -   0x1cfff3 +Foundation 751.32.0 (compatibility 300.0.0) <18F9E1F7-27C6-2B64-5B9D-BAD16EE5227A>
...

这是什么意思?我如何知道 0x59708e0 是哪个对象?我找不到导致我的应用程序崩溃的代码。我唯一知道的是它应该是一个respondsToSelector 消息。我向所有 respondsToSelector 消息添加了一个断点。他们被击中,但应用程序并没有在那时崩溃。我还尝试将它们注释掉,除了其中一个,并且还导致应用程序崩溃。没有被注释掉的,没有被击中。我哪里有内存泄漏?

下一个令人困惑的事情是 NSXML 解析器继续其工作,尽管调用了 parseErrorOccurred 委托。抛出错误两次后,应用程序崩溃。

为什么“运行中的僵尸”与性能工具被禁用?

编辑:

现在我使用了这个指令(无法发帖。抱歉。垃圾邮件预防)我得到了这个工作。这有什么意义呢?

@格雷厄姆: 在我的解析器类中,我实例化了 NSXMLParser:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {  
        ... 
    NSXMLParser *rssParser = [[NSXMLParser alloc] initWithData:responseData];  
    [rssParser setDelegate:self];
        ...
    [rssParser parse];
    //[rssParser release];
}

在搜索错误期间,我注释掉了release方法。目前 rssParser 从未在解析器类中发布。

在我的 RootViewController 类中,我实例化了我的解析器:

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

        XMLParser *rssParser = [[XMLParser alloc] init];  
        [rssParser parseRssFeed:@"http://feeds2.feedburner.com/TheMdnShowtest" withDelegate:self];  

        [rssParser release];
        rssParser = nil;

    } else {  
        [self.tableView reloadData];  
    }  
}

如果我不在这里释放它,它就不会崩溃。但是对于每个分配我都必须进行释放?或者我应该在 connectionDidFinishLoading 中自动释放 NSXMLParser

I try to find out why my app crashes (RSS Reader) if I send a wrong URL to NSXML Parser. I got an EXC_BAD_ACCESS. So after some Searching I found out that I have to use Zombies. So I added the following arguments to the environment:

CFZombieLevel = 3
NSMallocStaclLogging = YES
NSDeallocateZombies = NO
MallocStackLoggingNoCompact = YES
NSZombieEnabled = YES
NSDebugEnabled = YES
NSAutoreleaseFreedObjectCheckEnabled = YES

I also added malloc_error_break as breakpoint. Then I added some other breakpoints in the GUI and pressed Build and Debug. In the console I get the following message:

2010-08-28 18:41:49.761 RssReader[2850:207] *** -[XMLParser respondsToSelector:]: message sent to deallocated instance 0x59708e0

Sometimes I also get the following message:
wait_fences: failed to receive reply: 10004003

If I type in "shell malloc_history 2850 0x59708e0" I get the following:

...
ALLOC 0x5970870-0x59709d7 [size=360]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -[UIApplication
...
----
FREE  0x5970870-0x59709d7 [size=360]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication
...
ALLOC 0x59708e0-0x597090f [size=48]: thread_a0aaa500 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIApplication handleEvent:withNewEvent:] | -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] | -[UIApplication 
... 
Binary Images:
    0x1000 -     0x6ff3 +RssReader ??? (???) <6EBB16BC-2BCE-CA3E-C76E-F0B078995E2D> /Users/svp/Library/Application Support/iPhone Simulator/4.0.1/Applications/AF4CE7CA-88B6-44D4-92A1-F634DE7B9072/RssReader.app/RssReader
    0xe000 -   0x1cfff3 +Foundation 751.32.0 (compatibility 300.0.0) <18F9E1F7-27C6-2B64-5B9D-BAD16EE5227A>
...

What does this mean? How do I know which object 0x59708e0 is? I can't find the code which causes my app to crash. The only thing I know is that it should be a respondsToSelector message. I added a breakpoint to all my respondsToSelector messages. They get hitted but the app crashes not at that point. I also tried to comment them out except for one and also gets the app crashing. The one which was not commented out, wasn't hit. Where do I have a memory leak?

The next confusing thing is that NSXML Parser continue its' work, despite the parseErrorOccurred delegate is called. After two times an error is thrown, the app crashes.

Why is Zombies in the Run with Peformance Tool disabled?

Edit:

Now I used this instruction (not able to post. sorry. spam prevention) I got this working. What is the meaning of this?

@Graham:
In my parser class I instantiate NSXMLParser:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {  
        ... 
    NSXMLParser *rssParser = [[NSXMLParser alloc] initWithData:responseData];  
    [rssParser setDelegate:self];
        ...
    [rssParser parse];
    //[rssParser release];
}

During I searched the error, I commented out the release method. Currently rssParser never get's released in the parser class.

In my RootViewController class I instantiate my parser:

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

        XMLParser *rssParser = [[XMLParser alloc] init];  
        [rssParser parseRssFeed:@"http://feeds2.feedburner.com/TheMdnShowtest" withDelegate:self];  

        [rssParser release];
        rssParser = nil;

    } else {  
        [self.tableView reloadData];  
    }  
}

If I don't release it here, it doesn't crash. But for each alloc I have to do a release? Or should I autorelease NSXMLParser in connectionDidFinishLoading?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

简单气质女生网名 2024-09-23 06:04:04

当您将 Zombie 与内存泄漏一起使用时,它会被禁用,因为所有 Zombie 都会被标记为泄漏。要运行 Zombie 工具,您可以转到“仪器”菜单,执行“文件”>“新建”,然后单独选择 Zombie 工具,这样做,如果 Zombie 收到消息,程序将停止,并且您将在一个小弹出窗口中看到一个链接那个僵尸物体及其历史

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

笑红尘 2024-09-23 06:04:04

您在某个地方分配 XMLParser。让我们看看该代码。你不会自动释放它,是吗?

它在某个地方被释放......它被分配给一个属性吗?让我们看看该属性的定义。

稍后将调用respondsToSelector: 方法,但这可以是任何方法。关键是您的 XMLParser 在您预期之前就已经发布了。

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.

回忆凄美了谁 2024-09-23 06:04:04

在 RootViewController.h 中,我声明了属性 rssParser:

@class XMLParser;

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

@end

在 RootViewController.m 中,我有一个名为 errorOccurred 的方法:

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

在我的 XMLParser.m 文件中,我调用 errorOccurred 两次:

- (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:"];  
    }
}

要查看 _delegate 是如何声明的,请查看教程 http://www.cocoadevblog.com/iphone-tutorial-creating-a- RSS-提要-阅读器。它是一个 id 变量,并且有自己的 setter 和 getter 方法(我认为您也可以将其声明为属性)。第二次:

- (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:"];  
    }
}  

我的rssParser变量的释放如下:

在RootViewController.m中的loadData中我从未释放它。不幸的是,如果我在 loadData 中执行它,它会崩溃。仅当发生错误(见上文)或在 dealloc 方法中发生错误时才会释放它。但我认为这应该可以正常工作,因为它被声明为财产。

- (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];  
    }  
}

在 XMLParser.m 中,我在 parse 方法之后释放它:

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

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

    [rssParser setDelegate:self];

    [rssParser parse];

    [rssParser release];
    rssParser = nil;
}  

请注意,两个变量名称是相同的(rssParser),但它们是不同的。在 RootViewController 中,我创建了一个 XMLParser 实例,在 XMLParser.m 中,我创建了一个 NSXMLParser 实例。

所以我想我会保留它,直到我没有遇到新的错误或者你们中的人向我解释为什么这很糟糕。

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.

叹倦 2024-09-23 06:04:04

您是否还有 rssParser,您在此处设置释放的相同实例变量...

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

...在您的 dealloc 方法中释放?这将导致双重释放,从而导致 EXEC_BAD_ACCESS。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文