In my app im downloading some videos using NSURLConnection. It shows two memory warnings.
Received memory warning. Level=1
Received memory warning. Level=2
And then after sometime the App Crashes is there any way to solve this issue.
Can anyone help me with this issue.
Thanks in advance.
Code i used:
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:[exer1 objectAtIndex:i-1]]cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"%# urlrequest ",theRequest);
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain];
HUD.labelText =[NSString stringWithFormat:#"Downloading %d Video",[exer1 count]-(i-1)];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
expectedLength = [response expectedContentLength];
currentLength = 0;
HUD.mode = MBProgressHUDModeDeterminate;
NSLog(#"%d expectedLength",expectedLength);
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[HUD hide:YES];
// release the connection, and the data object
// [connection release];
// receivedData is declared as a method instance elsewhere
// [receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
if(tempz == 1){
tempz =0;
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"The Internet connection appears to be offline." message:nil delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *err;
NSFileManager *fman = [NSFileManager defaultManager];
NSString *path = [[[fman URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] path];
NSDictionary *fattr = [fman attributesOfFileSystemForPath:path error:&err];
//Error checking
NSUInteger freeSize = [[fattr objectForKey:NSFileSystemFreeSize] unsignedIntegerValue];
NSLog(#"Free Space %d", freeSize);
NSArray* paths1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
struct statfs tStats;
statfs([[paths1 lastObject] cString], &tStats);
float total_space = (float)(tStats.f_blocks * tStats.f_bsize);
NSLog(#"%f total_space",total_space);
[SavedVid addObject:[exer1 objectAtIndex:i-1]];
NSUserDefaults *currentDefaults6 = [NSUserDefaults standardUserDefaults];
[currentDefaults6 setObject:[NSKeyedArchiver archivedDataWithRootObject:SavedVid] forKey:#"SavedVid"];
[currentDefaults6 synchronize];
NSString* cacheDirectory = [NSHomeDirectory() stringByAppendingString:#"/Library/Caches"] ;
/* NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(#"%# documentsDirectory",documentsDirectory);
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
}
*/
NSString *file2 = [NSString stringWithFormat:#"%#/%#.mp4",cacheDirectory,[elementw.description objectAtIndex:i-1]];
/* NSLog(#"%# documentsDirectory",file2);
NSLog(#"%# ---- i elementw.description ---- %d ",elementw.description,i);
*/
[receivedData writeToFile:file2 atomically:YES];
NSLog(#" %# file 2 ",file2);
HUD.customView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]] autorelease];
HUD.mode = MBProgressHUDModeCustomView;
[HUD hide:YES afterDelay:2];
[self initializPlayer];
// release the connection, and the data object
// [connection release];
// [receivedData release];
}
When the data is received, you need to store it in a temporary (or not-so-temporary) file. The problem is that the whole file is being download into memory, which would consume most of the memory.
The application crashes because it's using too much memory, so writing to a file is the best option.
Something like this:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
NSString *temporaryFile = [NSString stringWithFormat:#"%#/fileDownload.part", NSTemporaryDirectory()];
if (![[NSFileManager defaultManager] fileExistsAtPath:temporaryFile]) {
[[NSFileManager defaultManager] createFileAtPath:temporaryFile contents:nil attributes:nil];
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:temporaryFile];
[fileHandle seekToEndOfFile];
[fileHandle writeData:data];
[fileHandle closeFile];
if (currentLength == expectedLength) {
//read from the file stored at temporaryFile
//perhaps move to a permanent location and change
//its file name and extension.
}
}
I think you are keeping the Video in your memory. Depending on the size it can cause memory problems.
Related
I am beginner of iPhone developer. I want to display data from server I have used below source code..
-(void)loadData:(id)sender
{
self.requestdata=[NSMutableData data];
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:kLatestKivaLoansURL]];
[[NSURLConnection alloc]initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[requestdata setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[requestdata appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection release];
self.requestdata=nil;
}
#pragma mark-
#pragma process loan data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responsedata=[[NSString alloc]initWithData:requestdata encoding:NSUTF8StringEncoding];
self.requestdata=nil;
NSDictionary *respDict = [[responsedata JSONValue]objectForKey:#"nodes"];
NSLog(#"Response Dict:%#",respDict);
NSMutableArray *arraY = [[NSMutableArray alloc]init];
arraY = [respDict mutableCopy];
NSLog(#"My array:%#",arraY);
NSString *mystr = [[[arraY objectAtIndex:0]valueForKey:#"node"]valueForKey:#"field_company_name_value"];
NSLog(#"Mystrname:%#",mystr);
NSArray *latestLoans=[(NSDictionary *)[responsedata JSONValue]objectForKey:#"responseData"];
NSLog(#"latest_dictionary:%#",latestLoans);
DisplayViewController *disp=[[DisplayViewController alloc]init];
for (int i = 0; i< [[latestLoans valueForKey:#"entries"] count] ; i++) {
// Search *aSearches = [[Search alloc] init];
NSDictionary *tempDict = [[latestLoans valueForKey:#"entries"] objectAtIndex:i];
// disp.link=[tempDict valueForKey:#"link"];
/*link = [tempDict valueForKey:#"link"];
aSearches.title = [tempDict valueForKey:#"title"];
aSearches.description = [tempDict valueForKey:#"contentSnippet"];
[appDelegate.search addObject:aSearches];*/
[appDelegate.disparray addObject:tempDict];
}
NSLog(#"DisplayArray:%#",appDelegate.disparray);
[self.view addSubview:disp.view];
/* DisplayViewController *disp=[[DisplayViewController alloc]initWithNibName:#"DisplayViewController" bundle:nil];
[self.navigationController pushViewController:disp animated:YES];*/
}
Please give any suggestion or source code which is apply in my code
Take a look at AFNetworking. It will do the job for you.
There is a specific method to handle JSON operations through the class AFJSONRequestOperation
Hope it helps.
http://www.touch-code-magazine.com/how-to-fetch-and-parse-json-by-using-data-models/
http://blog.zachwaugh.com/post/309924609/how-to-use-json-in-cocoaobjective-c
http://www.raywenderlich.com/5492/working-with-json-in-ios-5
http://json.org/
This is great tutorial for beginner, pls read this tutorial.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if(data != nil){
//open output stream
NSOutputStream *stream=[[NSOutputStream alloc] initToFileAtPath:_filePath append:YES];
[stream open];
NSString *str=(NSString *)data;
//write to file
NSUInteger left = [str length];
NSUInteger bytesWritten = 0;
do {
bytesWritten = [stream write:[data bytes] maxLength:left];
downloadedData = downloadedData + bytesWritten;
if (-1 == bytesWritten) break;
left -= bytesWritten;
} while (left > 0);
if (left) {
NSLog(#"stream error: %#", [stream streamError]);
[self handleForCurreptedDownloading];
}
[stream close];
}
else{
NSLog(#"data nil");
}
}
Tried with this code also but not working as it is giving same memory warning
downloadedData += [data length];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:_filePath];
[fileHandle seekToEndOfFile];
[fileHandle writeData:data];
[fileHandle closeFile];
This is the code i have used with fileSystem i am directly writing and appending into file. I have also used ARC. Still it is giving memory warning and getting crashed when i try to download large video files.
I have also checked before downloading the disk space
+ (NSNumber *)getFreeSpace
{
// float freeSpace = 0.0f;
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];
NSNumber *fileSystemFreeSizeInBytes = 0;
if (dictionary) {
fileSystemFreeSizeInBytes = [dictionary objectForKey: NSFileSystemFreeSize];
// freeSpace = [fileSystemFreeSizeInBytes floatValue];
} else {
//Handle error
}
return fileSystemFreeSizeInBytes;
}
I have checked with allocations and it is giving me the stable graph.
Is there any other way to download and manage large video files?
You are getting the complete downloaded file data in the didReceiveData function - which probably is HUGE.
I would use a framework like AFNetworking for your download needs, it makes things a lot simpler.
For example, for downloading large files without getting the whole data at once and then write it to a file, use a NSOutputStream to write parts of the file while they are downloaded.
This is from the AFNetworking documentation:
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:#"download.zip" append:NO];
I'm downloading the images from the online image for cache when offline. When I open application, The image was downloaded all completely before UIAlertView pop. It's finish incorrectly. I want to make the UIAlertView pop before images download. Here there are my code below.
- (void) operatePopupUpdating {
myAlert = [[UIAlertView alloc] initWithTitle:#"Updating database.." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[myAlert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(myAlert.bounds.size.width / 2, myAlert.bounds.size.height - 50);
[indicator startAnimating];
[myAlert addSubview:indicator];
[self operateUpdate];
[self updateImage];
[self operationCompleted];
}
In updateImage, operateUpdate and operationCompleted Method
- (void)updateImage {
NSString *snake_ico_file = #"snake_img_icn_";
NSString *filePath = [self dataFile:[snake_ico_file stringByAppendingString:#"0.jpg"]];
int max_count = [[self readData] count];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
for (int i = 0; i < max_count; i++) {
NSString *path = #"http://exitosus.no.de/drngoo/image/";
path = [path stringByAppendingFormat:#"%d",i];
NSString *ico_path = [path stringByAppendingFormat:#"/ico"];
//icon
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filename = [snake_ico_file stringByAppendingFormat:#"%d.jpg"];
NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:filename];
NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:ico_path]];;
[thedata writeToFile:localFilePath atomically:YES];
}
}
-(void) operationCompleted
{
[myAlert dismissWithClickedButtonIndex:0 animated:YES];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Message form System" message:#"Database was updated successful" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
- (void)operateUpdate {
NSString *filePath = [self dataFileSettingPath];
int updatedVer = 0;
int version = [self checkDatabase];
if (version == -1) {
updatedVer = [self createDataBase:0];
} else {
updatedVer = [self updateDataBase:version];
}
[self.settingInfo setObject:[NSString stringWithFormat:#"%d",updatedVer] forKey:#"DBVersion"];
[self.settingInfo writeToFile:filePath atomically:YES];
}
How I fix them and work correctly?
The alertView will show only after your image downloading complete. One Solution to solve this is,
Create another class ImageDownLoad.h
in .h
#property(nonatomic,assign)id delegate;
#property(nonatomic,retain) NSString *path;
in .m
#synthesize delegate;
#synthesize path;
Create a method namely,
-(void)startDownloadImageWithUrl:(NSURL*)imageUrl withLocalFilePath:(NSSTring*)filePath{
path = filePath;
receiveData = [NSMutableData data];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:imageUrl];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receiveData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
[(id)delegate performSelector:#selector(SaveData:inFilePath:) withObject:receiveData withObject:path];
}
This will create connection and start download your image in a separate class. Then in your mai ViewController add bit of code like below.
- (void)updateImage {
NSString *snake_ico_file = #"snake_img_icn_";
NSString *filePath = [self dataFile:[snake_ico_file stringByAppendingString:#"0.jpg"]];
int max_count = [[self readData] count];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
for (int i = 0; i < max_count; i++) {
NSString *path = #"http://exitosus.no.de/drngoo/image/";
path = [path stringByAppendingFormat:#"%d",i];
NSString *ico_path = [path stringByAppendingFormat:#"/ico"];
//icon
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filename = [snake_ico_file stringByAppendingFormat:#"%d.jpg"];
NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:filename];
ImageDownLoad *imageDown = [[ImageDownLoad alloc]init];
imageDown.delegate = self;
[imageDown startDownloadImageWithUrl:[NSURL URLWithString:ico_path] withLocalFilePath:localFilePath];
}
}
This method will be called each time when image download completes.
-(void)SaveData:(NSData*)data inFilePath:(NSString*)filePath{
[data writeToFile:filePath atomically:YES];
}
Your UI wont delay by doing so :)
I'm newbie in Objective-C, and as most of the newbies I have a questions about references management.
I've written a class which downloads data using NSURLConnection. The code is similar to Apple's example in http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html. The only difference is that receivedData variable is declared as "#property (nonatomic,retain) NSMutableData *receivedData;" In .m file I have "#synthesize receivedData = _receivedData;".
I have connectionStart function which starts downloading data. In this function I have this code:
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
self.receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed.
}
The program crashes with this message:
2011-06-12 12:47:22.298 WebGallery[1212:207] *** -[NSConcreteMutableData release]: message sent to deallocated instance 0x118a6fe0
If I change receivedData assignment to this code:
self.receivedData = [[NSMutableData data] retain];
Then the program works correctly and no memory leaks are detected.
As you see I need to call retain on NSMutableData and I'm using property, which is declared as "retain".
Why does this happen?
EDIT: Full contents of .m file:
#import "GalleryData.h"
#import "XmlParser.h"
#implementation GalleryData
#synthesize receivedData = _receivedData;
#synthesize imagesData = _imagesData;
#synthesize delegate = _delegate;
#synthesize currentObjectType = _currentObjectType;
#synthesize currentObjectIndex = _currentObjectIndex;
- (id) init
{
[super init];
_imagesData = [[NSMutableArray alloc] init];
return self;
}
- (void) dealloc
{
[_imagesData release];
_imagesData = nil;
[super dealloc];
}
- (void) connectionStart:(NSURL *)theURL
{
NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
//ASK: Kodėl čia reikia daryti retain jei #property jau nustatyta retain?
self.receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
- (void) startLoading
{
NSLog(#"Loading started");
self.currentObjectIndex = 0;
self.currentObjectType = ObjectTypeXML;
[self connectionStart:[NSURL URLWithString:#"http://www.aleksandr.lt/gallery/data.xml"]];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection release];
[self.receivedData release];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
if (self.currentObjectType == ObjectTypeXML) {
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:self.receivedData];
XmlParser *parser = [[XmlParser alloc] initXmlParser:self.imagesData];
[nsXmlParser setDelegate:parser];
[nsXmlParser parse];
[nsXmlParser release];
[parser release];
[self.receivedData release];
self.receivedData = nil;
if ([self.imagesData count]) {
self.currentObjectIndex = 0;
self.currentObjectType = ObjectTypeThumbImage;
ImageData *firstImage = [self.imagesData objectAtIndex:0];
NSURL *theURL = [NSURL URLWithString:firstImage.thumbImageURL];
[self connectionStart:theURL];
} else {
[self.delegate loadingFinished];
return;
}
} else if (self.currentObjectType == ObjectTypeThumbImage) {
ImageData *currentImage;
currentImage = [self.imagesData objectAtIndex:self.currentObjectIndex];
UIImage *thumbImage = [[UIImage alloc] initWithData:self.receivedData];
if (thumbImage == nil) {
NSLog(#"image was not created");
}
[currentImage setThumbImageScaled:thumbImage];
[thumbImage release];
[self.receivedData release];
self.receivedData = nil;
if (self.currentObjectIndex == ([self.imagesData count] - 1)) {
[self.delegate loadingFinished];
return;
}
self.currentObjectIndex++;
currentImage = [self.imagesData objectAtIndex:self.currentObjectIndex];
NSLog(#"'%#'", currentImage.thumbImageURL);
NSURL *theURL = [NSURL URLWithString:currentImage.thumbImageURL];
[self connectionStart:theURL];
}
}
#end
Do not call [self.receivedData release] - this leaves the internal pointer dangling. The whole point of a retained property is that it releases itself. Just do self.receivedData = nil.
Here is your problem:
[self.receivedData release];
self.receivedData = nil;
You're releasing the attribute twice (first time explicitly and second time implicitly by assigning nil).
I need to download large file (i.e. > 40MB) to my application from server, this file will be ZIP or PDF. I achieved it using NSURLConnection, that works well if the file is smaller other wise it download a part of the fill and the execution has stopped. for example I tried to download 36MB PDF file, but but 16MB only downloaded. pls help me to know the reason? how to fix it?
FYI:
Implementation File
#import "ZipHandlerV1ViewController.h"
#implementation ZipHandlerV1ViewController
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad
{
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)];
[mainView setBackgroundColor:[UIColor darkGrayColor]];
UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[downloadButton setFrame:CGRectMake(50, 50, 150, 50)];
[downloadButton setTitle:#"Download File" forState:UIControlStateNormal];
[downloadButton addTarget:self action:#selector(downloadFileFromURL:) forControlEvents:UIControlEventTouchUpInside];
[mainView addSubview:downloadButton];
[self setRequestURL:#"http://www.mobileveda.com/r_d/mcps/optimized_av_allpdf.pdf"];
[self.view addSubview:mainView];
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void) setRequestURL:(NSString*) requestURL {
url = requestURL;
}
-(void) downloadFileFromURL:(id) sender {
NSURL *reqURL = [NSURL URLWithString:url];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:reqURL];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
webData = [[NSMutableData data] retain];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error !" message:#"Error has occured, please verify internet connection" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[webData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[webData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *fileName = [[[NSURL URLWithString:url] path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];
NSString *filePath = [folder stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
NSError *writeError = nil;
[webData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
NSLog(#" Error in writing file %#' : \n %# ", filePath , writeError );
return;
}
NSLog(#"%#",fileURL);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error !" message:#"Error has occured, please verify internet connection.." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
#end
Header File:
#import <UIKit/UIKit.h>
#interface ZipHandlerV1ViewController : UIViewController {
NSMutableData *webData;
NSString *url;
}
-(void) setRequestURL:(NSString*) requestURL;
#end
Thank you,
Updated:
This happens because of my downloadable file was in shared hosting which having the download limitations. After I moved that file to dedicated server that working fine. and also I tried to download some other files like videos from some other sites, that also working fine.
So, if you having problem like partial download, don't only stick with the code, check the server too
You are currently keeping all downloaded data in a NSMutableData object which is kept within the RAM of your device. That will, depending on the device and the available memory, at some point trigger a memory warning or even a crash.
To get such large downloads to work, you will have to write all downloaded data directly to the filesystem.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//try to access that local file for writing to it...
NSFileHandle *hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
//did we succeed in opening the existing file?
if (!hFile)
{ //nope->create that file!
[[NSFileManager defaultManager] createFileAtPath:self.localPath contents:nil attributes:nil];
//try to open it again...
hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
}
//did we finally get an accessable file?
if (!hFile)
{ //nope->bomb out!
NSLog("could not write to file %#", self.localPath);
return;
}
//we never know - hence we better catch possible exceptions!
#try
{
//seek to the end of the file
[hFile seekToEndOfFile];
//finally write our data to it
[hFile writeData:data];
}
#catch (NSException * e)
{
NSLog("exception when writing to file %#", self.localPath);
result = NO;
}
[hFile closeFile];
}
I had the same problem, and seems that I discovered some solution.
In your header file declare:
NSMutableData *webData;
NSFileHandle *handleFile;
In your .m file on downloadFileFromURL when you get the connection initiate the NSFileHandle:
if (theConnection) {
webData = [[NSMutableData data] retain];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
handleFile = [[NSFileHandle fileHandleForWritingAtPath:filePath] retain];
}
then in didReceiveData instead of appending data to memory write it to disk, like this:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[webData appendData:data];
if( webData.length > SOME_FILE_SIZE_IN_BYTES && handleFile!=nil) {
[handleFile writeData:recievedData];
[webData release];
webData =[[NSMutableData alloc] initWithLength:0];
}
}
when the download finish on connectionDidFinishLoading add this lines to write the file and to release connection:
[handleFile writeData:webData];
[webData release];
[theConnection release];
I'm trying it right now, hope it works..
This happens because of my downloadable file was in shared hosting which having the download limitations. After I moved that file to dedicated server that working fine. and also I tried to download some other files like videos from some other sites, that also working fine.
So, if you having problem like partial download, don't only stick with the code, check the server too.
If you're willing to use asi-http-request, it's much, much easier.
Check out https://github.com/steipete/PSPDFKit-Demo for a working example with asi.
It's about as easy as this:
// create request
ASIHTTPRequest *pdfRequest = [ASIHTTPRequest requestWithURL:self.url];
[pdfRequest setAllowResumeForFileDownloads:YES];
[pdfRequest setNumberOfTimesToRetryOnTimeout:0];
[pdfRequest setTimeOutSeconds:20.0];
[pdfRequest setShouldContinueWhenAppEntersBackground:YES];
[pdfRequest setShowAccurateProgress:YES];
[pdfRequest setDownloadDestinationPath:destPath];
[pdfRequest setCompletionBlock:^(void) {
PSELog(#"Download finished: %#", self.url);
// cruel way to update
[XAppDelegate updateFolders];
}];
[pdfRequest setFailedBlock:^(void) {
PSELog(#"Download failed: %#. reason:%#", self.url, [pdfRequest.error localizedDescription]);
}];