在iphone中下载大型pdf(> 2MB)时,我的应用程序崩溃了

时间:2011-11-14 14:48:16

标签: iphone objective-c ios4 nsurlconnection asihttprequest

我的应用程序可以正常下载小Pdf并在WebView中显示它们,但是当我获取大小超过2 MB的pdf网址时,它每次都会崩溃。

代码: -

@implementation SecondViewController

@synthesize scrollView,receivedData,myIndicator;

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{   
    [receivedData appendData:data]; 
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    [myIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
    myIndicator.hidesWhenStopped = YES;
    [myIndicator startAnimating];

    UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"iphone_landscape.png"]];
    self.view.backgroundColor = background;
    [background release];   

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://litofinter.es.milfoil.arvixe.com/displayxml1.aspx"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:150.0];

    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {
        receivedData = [[NSMutableData data] retain];
    }

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    int x=10,y=50;

    appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];

    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 45,320, 480)];   
    scrollView.contentSize = CGSizeMake(320,5000);
    scrollView.showsVerticalScrollIndicator = YES;

    for (Litofinter *lito in appDelegate.bookArray) {
        if([appDelegate.currentButtonPressed isEqualToString:lito.cName])
        {
            NSLog(@"Count == %d ===",[lito.productsArray count]);
            for (Products *prod in lito.productsArray) {

                NSString * urlString = [prod.thumbnail stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
                NSURL * imageURL = [NSURL URLWithString:urlString];

                NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
                UIImage * image = [UIImage imageWithData:imageData];

                [myIndicator stopAnimating];
                [myIndicator removeFromSuperview];

                UIButton *imageButton = [[UIButton buttonWithType:UIButtonTypeCustom]retain];
                [imageButton setFrame:CGRectMake(x, y, 140, 190)];
                [imageButton setImage:image forState:UIControlStateNormal];
                [imageButton setTitle:prod.pdf forState:UIControlStateNormal];
                [imageButton addTarget:self action:@selector(onTapBook:) forControlEvents:UIControlEventTouchUpInside];

                [scrollView addSubview:imageButton];

                x = x + 160;

                if(x >300)
                {
                    y = y +250;
                    x = 10;

                }
            }
        }
    }
    [self.view addSubview:scrollView];

    [connection release];
    [receivedData release];


}

-(void)onTapBook:(id)sender{

    UIButton *button = (UIButton *) sender;
    appDelegate.currentBookPressed = [button currentTitle];
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Ver Catalogo!" message:@"" delegate:self cancelButtonTitle:@"Cancelar" otherButtonTitles:@"Ver on-line",@"Descargar",nil];
    [alert show];
}

// when I click on Descargar button i.e. download it goes to next PdfShowViewController

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex  
{  

    NSString *title = [alertView buttonTitleAtIndex:buttonIndex];  

    if([title isEqualToString:@"Ver on-line"])  
    { 
        viewController2 = [[PdfShowViewController alloc]initWithNibName:@"PdfShowViewController" bundle:nil];
        [self presentModalViewController:viewController2 animated:YES];

    }  

    else if([title isEqualToString:@"Descargar"])  
    {       
        viewController2 = [[PdfShowViewController alloc]initWithNibName:@"PdfShowViewController" bundle:nil];
        [self presentModalViewController:viewController2 animated:YES];
    }  

} 


-(IBAction)onTapBack{
    [self dismissModalViewControllerAnimated:YES];
}


- (void)dealloc {
    [super dealloc];
    [scrollView release];
}


@end

// here i am showing the pdf on a webView and downloading them

@implementation PdfShowViewController

@synthesize pdfWebview,myIndicator,progress,receivedData,DownloadRequest,DownloadConnection,downloadLabel,openURL;

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [receivedData appendData:data];

    unsigned char byteBuffer[[receivedData length]];
    [receivedData getBytes:byteBuffer];
    NSLog(@"Data === %ld",receivedData);

    NSInteger receivedLen = [data length];
    bytesReceived = (bytesReceived + receivedLen);
    NSLog(@"received Bytes ==  %f",bytesReceived);

    if(expectedBytes != NSURLResponseUnknownLength) 
    {
        NSLog(@"Expected Bytes in if ==  %f",expectedBytes);
        NSLog(@"received Bytes in if ==  %f",bytesReceived);

        float value = ((float) (bytesReceived *100/expectedBytes))/100;
        NSLog(@"Value ==  %f",value);
        progress.progress=value;
    }

}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [connection release];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    expectedBytes = [response expectedContentLength];
    NSLog(@"%f",expectedBytes);

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    [myIndicator stopAnimating];
    [myIndicator removeFromSuperview];
    [progress setHidden:YES];
    [downloadLabel setHidden:YES];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:@"MayankPdf.pdf"];

    unsigned char byteBuffer[[receivedData length]];
    [receivedData getBytes:byteBuffer];

    [self.receivedData  writeToFile:pdfPath atomically:YES];

    [connection release];

    //Now create Request for the file that was saved in your documents folder

    NSURL *url = [NSURL fileURLWithPath:pdfPath];

    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];

    [pdfWebview setScalesPageToFit:YES];
    [pdfWebview loadRequest:requestObj];
}

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];

    [downloadLabel setText:@"Downloading..."];
    [downloadLabel setHidden:NO];

    [myIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
    myIndicator.hidesWhenStopped = YES;
    [myIndicator startAnimating];

    NSLog(@"REquired --------------------------------%@",appDelegate.currentBookPressed);
    //  NSString *urlString = [appDelegate.currentBookPressed stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
    NSString *urlString = [appDelegate.currentBookPressed stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    NSLog(@"The Url Stirng=======%@",urlString);

    NSURL *targetURL = [NSURL URLWithString:urlString];
    NSLog(@"Trageted String ------======++++++++%@",targetURL);
    DownloadRequest = [NSURLRequest requestWithURL:targetURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:120.0];
    DownloadConnection = [[NSURLConnection alloc] initWithRequest:DownloadRequest delegate:self];

    if (DownloadConnection) {
        receivedData = [[NSMutableData data]retain];
    }

    [pdfWebview setScalesPageToFit:YES];
    //  [pdfWebview loadRequest:DownloadRequest];


}

-(IBAction)onTapBack
{
    [self dismissModalViewControllerAnimated:YES];
}

- (void)dealloc {
    [super dealloc];
    [pdfWebview release];
    //  [receivedData release];
}


@end

我的解析器也不接受有空格的URL,任何解决方案都将受到赞赏。提前致谢

请原谅我写错了,因为我在Iphone上不是很好。

3 个答案:

答案 0 :(得分:1)

根据您在评论中所说的内容(应用程序在设备上崩溃但未在模拟器上崩溃)并考虑到您正在下载大型PDF文件,我的猜测是您遇到内存问题并且您的应用程序被系统(这通常与关于发送给应用程序的信号0的日志消息相关联。)

如果是这样,我建议您逐步存储下载的数据;即,您不会在NSData中附加所有数据,并且在最后(当您获得所有数据时)将它们存储到文件中。您可以将每个收到的块附加到文件中并释放内存。

另一方面,我不太清楚为什么要这样做:

unsigned char byteBuffer[[receivedData length]];
[receivedData getBytes:byteBuffer];

因为您未在byteBuffer方法中的其他地方使用connectionDidFinishLoading。我认为这不是问题的原因,因为此后局部变量被释放,但是如果你收到大量数据,你仍然会复制它(一次在NSData中,第二次在堆栈上)。

关于网址中的空间问题,您应该考虑使用

转义它们
stringByAddingPercentEscapesUsingEncoding:

这是NSString方法。

答案 1 :(得分:1)

你分配的大部分东西都没有被释放(连接,警报,视图控制器2)

[connection release];中的第- (void)connectionDidFinishLoading:(NSURLConnection *)connection个您要发布的连接

清除此问题后,请检查并运行该应用。然后解释你的异常或错误。

答案 2 :(得分:1)

你的RAM限制可能超过30MB,

您不应该使用NSMutableData对象来重建整个文件,而是直接将其写在“磁盘”上以限制内存使用。

激励你

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    @synchronized(connection) {
        m_downloadedBytes += [data length];
        CGFloat downloadProgress = ((CGFloat) m_downloadedBytes / (CGFloat) m_fileSize);
        [self setDownloadProgress:downloadProgress];        

        if (!m_fileHandle) {
            [data writeToURL:m_tmpTargetURL atomically:NO];
            m_fileHandle = [[NSFileHandle fileHandleForWritingToURL:m_tmpTargetURL error:NULL] retain];
            [m_fileHandle seekToEndOfFile];
        }
        else {
            [m_fileHandle writeData:data];

        }
    }
}