两次NSURLConnection崩溃

时间:2014-06-15 13:06:20

标签: ios iphone objective-c nsurlconnection nsurlconnectiondelegate

我使用以下地址下载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来创建请求文件。我在方法中使用它并一次又一次地调用此方法。因为网址在每次通话时都在变化。可能有这个问题吗?

7 个答案:

答案 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,你需要使用下面的代码片段。它具有管理的所有功能,只要性能,安全性,泄漏等都受到关注,所有方面都已经管理好,所以你不需要为所有这些事情花费任何开销。

你只需要

  1. 从上面的链接下载开源代码文件
  2. 通过拖放将其集成到您的项目中
  3. 将以下功能复制并粘贴到各自的控制器
  4. 将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. 我希望这会帮助你。

答案 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这个视图时,我的问题已得到解决。

感谢所有朋友的回复。