我的应用程序与iOS5 b7和GM版本的兼容性存在问题。
问题出现在下一行代码中:
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
在一些迭代后,应用程序与信号EXC_BAD_ACCESS
崩溃。
传递的迭代次数是随机的(从2到7)。
在iOS4和iOS3上,一切都运行良好。
Apple的示例中出现了同样的问题:XMLPerformance Sample。
您如何看待这个?
10月12日我的应用程序的数千名用户将升级到iOS5,我不希望我的应用程序在AppStore中出现如此奇怪的错误。
答案 0 :(得分:10)
过了4个小时,我发现了问题。我将在XMLPerformance sample
中描述我是如何解决问题的。
问题出在NSAutoreleasePool
。有@property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;
。当应用程序开始下载Top300 Paid Apps RSS
时,使用[NSThread detachNewThreadSelector:@selector(downloadAndParse:) toTarget:self withObject:url];
创建新线程。所以在那个线程中我们应该保留本地自动释放池。它以下一种方式完成:
- (void)downloadAndParse:(NSURL *)url {
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
// initializing internet connection and libxml parser.
if (rssConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release resources used only in this thread.
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
}
所以在downloadAndParse:
一切都很好。现在让我们看一下在解析RSS中的项时调用的一个方法:
- (void)finishedCurrentSong {
// sending new item to delegate and other ...
countOfParsedSongs++;
// Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the
// size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but
// taking this action too frequently would be wasteful and reduce performance.
if (countOfParsedSongs == kAutoreleasePoolPurgeFrequency) {
[downloadAndParsePool release];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
countOfParsedSongs = 0;
}
}
如你所见:
[downloadAndParsePool release];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
确切地说,这些行会导致异常。如果我评论他们一切都很好。
但我决定不仅要对这些行进行评论,还要将NSAutoreleasePool
中的- (void)downloadAndParse:(NSURL *)url
替换为@autorelease
块,因为据说它更有效:
- (void)downloadAndParse:(NSURL *)url {
@autoreleasepool {
// initializing internet connection and libxml parser.
if (rssConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release resources used only in this thread.
}
}
现在一切正常。我没有解决的唯一问题是:
// Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the
// size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but
// taking this action too frequently would be wasteful and reduce performance.
因此,如果有人对此问题有任何想法,可以发布另一个答案,并可能尝试更正确地解释错误修复。我很乐意接受这个答案。
感谢。
答案 1 :(得分:2)
这看起来像内存问题,请查看Apple Technote QA1367“Finding EXC_BAD_ACCESS bugs in a Cocoa project”
在您的代码中,请尝试尽快崩溃:
[item release], item = nil;
它没有解决问题,只是让崩溃发生得更早,希望能给你一个更有意义的学习问题。
如果您正在使用多线程,那么......您可以尝试将“当前”线程ID打印到控制台中,以验证所有内容是否都在您期望它们的线程中运行运行。特别要验证所有UI内容都在主线程中,即使这些代码作为其他代码的副作用运行(可能是错误弹出窗口)。
#include <pthread.h>
- (void)myFunction
{
NSLog(@"Thread (%d)",
pthread_mach_thread_np(pthread_self()));
}
使用乐器运行您的应用,确保每1或2秒更改一次内存验证。慢,但你想再次收到尽可能接近实际内存问题的通知。
答案 2 :(得分:1)
查看您的代码:“完成”变量来自哪里,谁改变了它的价值?何时?现在看起来很神奇。
您还可以检查runMode:beforeDate 的返回值,以确保它已运行。如果返回值为NO,则根本不运行runLoop。也许你的代码的其他部分无法处理这种情况?
答案 3 :(得分:0)
只是我的小贡献。
由于我遇到了同样的问题,我发现在iOS5中,您不需要在线程中使用自己的NSAutoreleasePool(由performSelectorOnMainThread使用)。
然后,在你的代码中(xml解析器 - 和我一样),我认为你必须将代码与iOS4和iOS5分开。
使用iOS4,您需要NSAutoreleasePool,但不需要iOS5。