我有一个小应用程序可以下载股票价格并且完美运行(多年),直到我最近升级到10.5.7.升级后,程序将在此调用时崩溃:
NSString *currinfo = [NSString stringWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]]];
奇怪的是,崩溃不会马上发生.这行代码被多次调用,没有任何问题,然后由于此调用崩溃,程序最终会在1-2小时后失败.
我原本在这里发了一篇很长的帖子,描述了我试图调查这个问题.我收到了两个建议:(i)使调用异步(可能更好)和(ii)使用NSZombieEnabled来调查Objective-C对象提前解除分配的可能性(此注释是为了响应显示失败的堆栈跟踪而做出的objc_msgSend).
我花了很多时间使调用异步(使用[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]),这没有帮助.该计划最终仍然失败,通常在10-15分钟后.在失败之前的这段时间内,许多异步调用没有任何问题,数据被返回等等.一切都很好.然后程序突然再次崩溃.
然后我打开了NSZombieEnabled.果然,当程序最终崩溃时,我收到了消息:
-[CFArray count]: message sent to deallocated instance 0x16b90bd0
"info malloc 0x16b90bd0"随后产生:
0: 0x93db810c in malloc_zone_malloc 1: 0x946bc3d1 in _CFRuntimeCreateInstance 2: 0x9464a138 in __CFArrayInit 3: 0x946cd647 in _CFStreamScheduleWithRunLoop 4: 0x932d1267 in _Z16_scheduleRStreamPKvPv 5: 0x946bf15c in CFSetApplyFunction 6: 0x932b0e2b in CFNSchedulingSetScheduleReadStream 7: 0x9331a310 in _ZN12HTTPProtocol19createAndOpenStreamEv 8: 0x9332e877 in _ZN19URLConnectionLoader24loaderScheduleOriginLoadEPK13_CFURLRequest 9: 0x9332d739 in _ZN19URLConnectionLoader26LoaderConnectionEventQueue33processAllEventsAndConsumePayloadEP20XConnectionEventInfoI12XLoaderEvent18XLoaderEventParamsEl 10: 0x9332dbdd in _ZN19URLConnectionLoader13processEventsEv 11: 0x932d8dbf in _ZN17MultiplexerSource7performEv 12: 0x946ba595 in CFRunLoopRunSpecific 13: 0x946bac78 in CFRunLoopRunInMode 14: 0x9058c530 in +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] 15: 0x90528e0d in -[NSThread main] 16: 0x905289b4 in __NSThread__main__ 17: 0x93de8155 in _pthread_start 18: 0x93de8012 in thread_start
我不是读取堆栈跟踪的专家,但是这条跟踪是否表明Apple代码中存在问题,而不是我的代码?或者我可以以某种方式负责取消分配有问题的CFArray?我有什么方法可以进一步调查问题的原因吗?
(这是我原帖的其余部分)
看到这个stringWithContentsOfURL
已被弃用,我切换到这段代码:
pathURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://finance.yahoo.com/d/quotes.csv?s=%@&f=l1c1p2", escsymbol]]; NSURLRequest *request = [NSURLRequest requestWithURL:pathURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0]; responseData = [ NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; NSString *currinfo = nil; if ([error code]) { dNSLog((@"%@ %d %@ %@ %@", [ error domain], [ error code], [ error localizedDescription], request, @"file://localhost/etc/gettytab")); }
这没有用.程序sendSynchronousRequest
在任意长度的时间后仍然在线路上崩溃,调试器中包含以下信息:
0 0x93db7286 in mach_msg_trap 1 0x93dbea7c in mach_msg 2 0x946ba04e in CFRunLoopRunSpecific 3 0x946bac78 in CFRunLoopRunInMode 4 0x932b53eb in CFURLConnectionSendSynchronousRequest 5 0x905dca4b in +[NSURLConnection sendSynchronousRequest:returningResponse:error:]
...等等.
真正的崩溃实际上可能在另一个线程中:
0 libobjc.A.dylib 0x965c3688 objc_msgSend + 24 1 com.apple.CoreFoundation 0x946cc581 _CFStreamSignalEventSynch + 193 2 com.apple.CoreFoundation 0x946ba595 CFRunLoopRunSpecific + 3141 3 com.apple.CoreFoundation 0x946bac78 CFRunLoopRunInMode + 88 4 com.apple.Foundation 0x9058c530 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 320 5 com.apple.Foundation 0x90528e0d -[NSThread main] + 45 6 com.apple.Foundation 0x905289b4 __NSThread__main__ + 308 7 libSystem.B.dylib 0x93de8155 _pthread_start + 321 8 libSystem.B.dylib 0x93de8012 thread_start + 34
我认为是生成下载URL的线程.顺便说一句,错误处理代码工作正常 - 当我故意通过断开互联网导致错误时,错误只是在控制台中报告,程序不会崩溃.
这令人难以置信地令人沮丧.我会非常乐意花费尽可能多的时间来追踪问题,但我对gdb的知识极限,尤其是汇编语言.我不知道如何找出Foundation代码的实际问题.起初我以为自动释放可能NSString escsymbol
会以某种方式被释放,但发送保留消息并没有帮助.如果是这种情况,我怎么能证明呢?
有人有这个问题吗?
我认为Eugene在这个帖子中的回答恰当地描述了这个问题; 经过一些测试后,我已经得出结论似乎正在进行中,希望有一些细节可以帮助其他人解决这个问题:
重定向URL会定期导致失败.这在同步和异步使用中都会发生NSURLConnection
.我已经创建了一个测试项目来跟踪这个bug,并且这种崩溃将持续发生(通常在25-500次迭代之间).在10.5.6上运行相同的测试或不重定向URL不会失败(最多运行20,000次迭代).
有两种可能的解决方法:
不要使用重定向URL:
显然这并不总是可行,但如果它是一个已知的URL,你仍然可以使用简单的调用(如stringWithContentsOfURL:
),这将正常工作.丹尼斯,你的情况,适当的服务器URL是download.finance.yahoo.com
,不是finance.yahoo.com
,所以我相信这将解决您的特定问题.使用curl
您可以看到当您点击后一个地址时获得301重定向.
使用异步调用和实现connection:willSendRequest:redirectResponse:
如果您实现了对此委托方法的最基本处理,一切似乎都有效.如果你省略这个调用(从而让系统使用它的默认实现),你就会崩溃.对于基本实现,只需返回传入的请求:
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *) redirectResponse { return request; }
所有这些似乎都告诉我,Apple在10.5.7中的实现中存在一些问题,但如果其他人对可能发生的事情有任何见解,请发出声音.
我已将我的测试项目的错误提交给Apple,rdar://6936109
并引用了tjw的报告(Radar 6932684).
这似乎与重定向有关.我的应用程序直接下载大约500兆的数据(几百个单独的文件)不会崩溃.同样的应用程序下载较小的url集,所有这些都被重定向将在这一点上随机崩溃几次(重启恢复,重复重新启动实际上会导致成功下载).
编辑:BTW,科林关于重新实现重定向的建议似乎不适用于NSURLDownload :(.
编辑2:好的,这似乎是竞争条件.添加cerr <<"redirect"<< endl; 在回调中"通过NSURLDownload"修复了它.睡眠1秒或锁定本地静态互斥锁无效...