我使用以下地址下载mp3文件。我有一个uitoolbarbutton
,当点击此按钮时,我会调用downloadandCreatePath
,然后创建一个包含我的`downloadProgressV'以及取消下载的UIButton。
我点击下载视图出现并下载。下载成功完成,如果我取消,它也可以正常工作。
问题是,如果我第二次,然后第三次。该应用程序第三次在EXC_BAD_ACCESS
上显示appdelegate
消息时崩溃。
NSURLResponse *urlResponse;
NSMutableData *downloadedMutableData;
NSURLConnection *connectionManager;
- (NSString *) downloadandCreatePath: (int) doaId
{
@try {
self.downloadProgressV.progress=0.0;
self.downloadView.hidden=NO;
NSString *stringURL = @"http://www.ergmusic.com/mp3-samples/488000/488799.mp3";
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:stringURL]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
connectionManager = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (!connectionManager) {
// Release the receivedData object.
downloadedMutableData = nil;
// Inform the user that the connection failed.
}
}
@catch (NSException *exception) {
NSLog(@"buuuuuuug");
return @"";
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[downloadedMutableData setLength:0];
urlResponse = response;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[downloadedMutableData appendData:data];
self.downloadProgressV.progress = ((100.0/urlResponse.expectedContentLength)*downloadedMutableData.length)/100;
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
connectionManager = nil;
downloadedMutableData = nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.downloadProgressV.progress=0.0;
self.downloadView.hidden = YES;
connectionManager = nil;
downloadedMutableData = nil;
}
- (IBAction)cancelDownloadTouchUpInside:(id)sender {
self.downloadView.hidden=YES;
[connectionManager cancel];
connectionManager = nil;
downloadedMutableData = nil;
}
有人知道我的问题在哪里吗?
更新
我尝试使用以下说明使用nszombies
调试应用:
http://michalstawarz.pl/2014/02/22/debug-exc_bad_access-nszombie-xcode-5/
但这次错误并不存在。
更新
我在NSMutableData
方法中设置了viewdidload
。
此外,我尝试在downloadandCreatePath
的第一行实例化它,但我仍然看到错误。
更新
在 2次运行之后以及我想尝试初始化connectionManager
时发生错误。我想知道为什么经过两次运行后,在第三次尝试问题发生。为什么它在第一次运行后和第二次尝试时不能生效?!!
更新
我认为下面的堆栈跟踪更好:
<_NSCallStackArray 0x94ee270>(
0 ??? 0x097c85cf 0x0 + 159155663,
1 MafatihTebyan 0x00010cb4 -[DoaShowViewController downloadandCreatePath:] + 404,
2 MafatihTebyan 0x000114be -[DoaShowViewController DisplayDoaPlayView:] + 94,
3 libobjc.A.dylib 0x0181f874 -[NSObject performSelector:withObject:withObject:] + 77,
4 UIKit 0x0057d0c2 -[UIApplication sendAction:to:from:forEvent:] + 108,
5 UIKit 0x00851c9b -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139,
6 libobjc.A.dylib 0x0181f874 -[NSObject performSelector:withObject:withObject:] + 77,
7 UIKit 0x0057d0c2 -[UIApplication sendAction:to:from:forEvent:] + 108,
8 UIKit 0x0057d04e -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61,
9 UIKit 0x006750c1 -[UIControl sendAction:to:forEvent:] + 66,
10 UIKit 0x00675484 -[UIControl _sendActionsForEvents:withEvent:] + 577,
11 UIKit 0x00674733 -[UIControl touchesEnded:withEvent:] + 641,
12 UIKit 0x005ba51d -[UIWindow _sendTouchesForEvent:] + 852,
13 UIKit 0x005bb184 -[UIWindow sendEvent:] + 1232,
14 UIKit 0x0058ee86 -[UIApplication sendEvent:] + 242,
15 UIKit 0x0057918f _UIApplicationHandleEventQueue + 11421,
16 CoreFoundation 0x01a1383f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15,
17 CoreFoundation 0x01a131cb __CFRunLoopDoSources0 + 235,
18 CoreFoundation 0x01a3029e __CFRunLoopRun + 910,
19 CoreFoundation 0x01a2fac3 CFRunLoopRunSpecific + 467,
20 CoreFoundation 0x01a2f8db CFRunLoopRunInMode + 123,
21 GraphicsServices 0x0303b9e2 GSEventRunModal + 192,
22 GraphicsServices 0x0303b809 GSEventRun + 104,
23 UIKit 0x0057bd3b UIApplicationMain + 1225,
24 MafatihTebyan 0x00008a2d main + 141,
25 libdyld.dylib 0x03c1d725 start + 0,
26 ??? 0x00000001 0x0 + 1
)
重要更新
我注意到即使在第一次通话时,代码也无法在iOS 6上运行。在iOS 6中,它一直都在崩溃。
更新
我在NSURLConnection
看到的所有示例都使用viewdidload
来创建请求文件。我在方法中使用它并一次又一次地调用此方法。因为网址在每次通话时都在变化。可能有这个问题吗?
答案 0 :(得分:2)
如果您在第一次下载之前启动第二次下载,如果您重新实例化NSMutableData
(您没有向我们展示),则旧的NSMutableData
将被释放,从而导致与僵尸有关的错误。您需要维护一个NSMutableData
对象数组,或者为每次下载实例化一个新的委托对象。
答案 1 :(得分:0)
不确定您在哪里初始化了已下载的DataData。我在didRecieveData方法中使用了以下内容:
if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:10240]; }
然后是appendData:line。
答案 2 :(得分:0)
您正在销毁 downloadedMutableData 对象。 不要将它设置为nil,而是使用setLength:0。
答案 3 :(得分:0)
不要将downloadedMutableData设置为nil。
改为使用
[downloadedMutableData resetBytesInRange:NSMakeRange(0, [downloadedMutableData length])];
另外,为确保在任何给定时间只能运行一个下载任务,请为NSURLConnection任务创建单独的NSOperationQueue。将maxConcurrentOperationCount属性设置为1将为您的下载创建FIFO队列。
NSOperationQueue *queue=[[NSOperationQueue alloc]init];
queue.maxConcurrentOperationCount=1;
[queue addOperationWithBlock:^{
YourDownloadCode...
}];
答案 4 :(得分:0)
@Husein BehbudiRad
我建议您使用经过良好测试和发布的开源库,以便将文件上载到服务器或从服务器下载文件。我说的是AFNetworking,你需要使用下面的代码片段。它具有管理的所有功能,只要性能,安全性,泄漏等都受到关注,所有方面都已经管理好,所以你不需要为所有这些事情花费任何开销。
你只需要
将NSString格式的url和要将其存储到文件目录的文件名传递给下面的函数,你就可以了..
-(BOOL)fileDownloadWithUrl:(NSString*)urlStr withFilename:(NSString*)fileName
{
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:fileName];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Successfully downloaded file to %@", path);
return TRUE;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
return FALSE;
}];
[operation start];
}
我希望这会帮助你。
答案 5 :(得分:0)
您有多个连接重用相同的委托。您可能已取消之前的连接,但代理仍将获取先前连接的消息。在每个委托消息中,检查传入连接的地址与[self connectionManager]
的地址。
示例:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (connection == [self connectionManager]){
connectionManager = nil;
downloadedMutableData = nil;
}
}
在取消连接或重新分配连接后,您还应将连接的委托设置为nil。您似乎没有取消之前的连接。 例如:
if ([self connectionManager] != nil){
[[self connectionManager] cancel];
/// Optional, if you are not interested in getting remaining delegate messages.
[[self connectionManager] setDelegate:nil];
[self setConnectionManager:nil];
}
connectionManager = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
尽管如此,因为您正在重新使用这样的委托,所以您还应该考虑在接收连接其他的消息时如何处理当前连接。例如,如果取消连接,委托可能会获得didFinishLoading或didFailWithError回调。如果您将一个可以飞行的连接设置为nil,这也可能会发生这种情况。
答案 6 :(得分:0)
感谢所有回复和帮助。
最后,@ quellish和@Kuldeep在评论中说。我注意到问题与NSURLConnection
无关。这是因为我正在显示我创建的下载进度视图。请参阅我问题的第二行。
当我不使用它而不是使用MBProgressHUD
这个视图时,我的问题已得到解决。
感谢所有朋友的回复。