2010-08-28 30 views
4

我试图找出为什么我的应用程序崩溃(RSS阅读器),如果我发送错误的URL到NSXML解析器。我得到了EXC_BAD_ACCES S.所以在一些搜索之后,我发现我必须使用僵尸。所以我在环境中添加了以下参数:respondsToSelector发送到释放对象

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

我还加了malloc_error_break作为断点。然后我在GUI中添加了一些其他断点,并按下了Build and Debug。在控制台中我得到以下信息:

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

有时候,我也得到了以下信息: wait_fences: failed to receive reply: 10004003

如果我输入“壳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委托。在两次抛出错误之后,应用程序崩溃。

为什么僵尸在运行与性能工具被禁用?

编辑:

现在我用这个指令(无法发布对不起防止垃圾邮件。)我得到了这个工作。这是结果:http://yfrog.com/mrzombievp那么这是什么意思?

@Graham: 在我的分析器类我实例NSXMLParser

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

在我搜索的错误,我注释掉的释放方法。目前rssParser从未在解析器类中获得发布。

在我RootViewController I类实例化我的解析器:

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

回答

1

在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-feed-reader。它是一个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变量的版本是这样的:

在loadData在RootViewController.m我从来没有松开。不幸的是,如果我在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我释放它的解析方法之后:

- (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实例。

所以我认为我会放弃它,直到我没有遇到新的错误或者你的某个人解释为什么这是坏的。

1

由于所有的僵尸都会以泄漏的方式发出信号,僵尸会因为内存泄漏而被禁用。要运行僵尸工具,您可以进入仪器菜单并执行文件>新建,然后单独选择僵尸工具,这样一来,如果僵尸收到了一条消息,程序就会停止,并且您会在小弹出窗口中获得链接到僵尸对象及其历史记录

+0

感谢您的提示!我在阅读时意识到这一点http://www.corbinstreehouse.com/blog/2007/10/instruments-on-leopard-how-to-debug-those-random-crashes-in-your-cocoa-app/ 我并不知道Instruments是独立程序,不属于Xcode。不过,我不明白他们为什么会提供该菜单条目,如果它不能使用。 – testing 2010-08-29 09:53:34

1

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

某处它被释放......它被分配给一个属性?我们来看看这个属性定义。

稍后调用respondsToSelector:方法,但可以是任何方法。关键是你的XMLParser在你打算之前就已经发布了。

+0

所以我编辑了我的问题。我使用的是alloc,所以我不认为我正在自动释放它。我不使用RSS解析器作为属性。什么时候该发布它? – testing 2010-08-29 09:58:47

+0

看起来像您的XMLParser类正在期待一些异步I/O响应?如果是这样,它需要四处走动直到完成。因此你不能在loadData中释放它。 在connectionDidFinishLoading中自动释放本身:如果这是在完成处理时值得尝试。您也必须在任何连接错误处理方法中执行相同的操作。 – 2010-08-29 12:36:41

+0

我没有看过同步/异步的东西。所以我要告诉你我使用什么。我使用NSURLConnection和NSXMLParser。 NSURLConnection创建异步连接,NSXMLParser是SAX解析器。由于我在connectionDidFinishLoading中开始解析:解析发生在下载文件时(错误文件是一个HTML文件,5秒后重定向发生)。该项目基于本教程:http://www.cocoadevblog.com/iphone-tutorial-creating-a-rss-feed-reader。 – testing 2010-08-30 08:12:41

1

你也有rssParser,你在这里可以设置释放相同的实例变量...

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

...在你的dealloc方法释放?这将导致一个双重释放,并因此导致EXEC_BAD_ACCESS。

+0

好点!这个问题太旧了,我不记得了。抱歉。在我目前的项目中,'errorOccured'中不再有发布。 – testing 2011-01-14 23:56:41

相关问题