Downloading large videos gives memory warning - iphone

-(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];

Related

Some strange error occurs when manipulating events in the calendar of iOS device

I added some events to the calendar and save their eventIdentifier to file. When i want to remove all my events i read the eventIdentifier from that file to an array and remove each event with its event id. Here is the code to add event to calendar and save their event id to file:
- (void) addEventToCalendar: (id)object
{
#autoreleasepool {
int i = 0;
NSString *string_to_file = #"";
eventStore=[[EKEventStore alloc] init];
for(Schedule *sche in scheduleArray){
EKEvent *addEvent=[EKEvent eventWithEventStore:eventStore];
addEvent.title=sche.course_Name;
addEvent.startDate = [self stringToDate:sche.from_Date];
addEvent.endDate = [self stringToDate:sche.thru_Date];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
NSDate *date_alarm = [addEvent.startDate dateByAddingTimeInterval:-(10*60)];
addEvent.alarms=[NSArray arrayWithObject:[EKAlarm alarmWithAbsoluteDate:date_alarm]];
NSError *err;
// do save event to calendar
[eventStore saveEvent:addEvent span:EKSpanThisEvent error:&err];
if (err == nil) {
NSString* str = [[NSString alloc] initWithFormat:#"%#", addEvent.eventIdentifier];
string_to_file = [string_to_file stringByAppendingString:str];
string_to_file = [string_to_file stringByAppendingString:#"\n"];
NSLog(#"String %d: %#",i, str);
}
else {
NSLog(#"Error %#",err);
}
i++;
}
// create file to save
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
inFile = [NSFileHandle fileHandleForWritingAtPath: filePath];
NSData *data = [string_to_file dataUsingEncoding:NSUTF16StringEncoding];
[inFile writeData:data];
}
}
And the code below to remove all events i have added to calendar
- (void) deleteEventInCalender {
filemgr = [NSFileManager defaultManager];
NSString *filePath = [self getFilePath:#"saveeventid.txt"];
NSFileHandle *inFile;
inFile = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *dataFile;
dataFile = [inFile readDataToEndOfFile];
NSString *tmp = #"";
NSString *temp = #"";
tmp = [NSString stringWithCharacters:[dataFile bytes] length:[dataFile length]/sizeof(unichar)];
if(![tmp isEqualToString:#""]){
tmp = [tmp substringFromIndex:1];
event_idArray = [[NSMutableArray alloc] init];
int j = 0;
while (![tmp isEqualToString:#""]){
int index_find_string = [tmp rangeOfString:#"\n"].location;
temp = [tmp substringWithRange:NSMakeRange(0, index_find_string)];
[event_idArray addObject:temp];
tmp = [tmp substringFromIndex:index_find_string + 1];
}
EKEventStore* store = [[EKEventStore alloc] init];
j = 0;
for(NSString *eventid in event_idArray){
EKEvent* event2 = [store eventWithIdentifier:eventid];
if (event2 != nil) {
NSLog(#"log: %d log id: %#", j, eventid);
NSError* error = nil;
// remove event
[store removeEvent:event2 span:EKSpanThisEvent error:&error];
}
j++;
}
[filemgr removeItemAtPath:filePath error:nil];
}
}
All codes above work well when i test on the iOS simulator with calendar.sqlitedb. But it makes some strange errors when i run on iPad device 5.0. That is sometime the calendar not remove event or when all events has been remove then after some minutes all events appear again... I don't understand, i don't know why and i very confuse. Does anyone has the same issue with me? Please share your solution!
Added another question: where the calendar database stored in the iOS 5.0 device.

XML Tag xcode save file

I would like to output tags for each line with different tag names and want to save each in a file. I can write the file, but it is over writing. How do I write each and every line in a different file?
Input:
english titanic
leondradicapro kate
German Hotel hüßßan
tomhanks angleina
Output:
<language>english<language/>
<movie>titanic<movie/>
<Actor>leondradiacpro<Actor/>
<Actress>kate<Actress/>
<language>German<language/>
...
Code:
for (NSString *str in lineFile)
{
if([str hasPrefix:#"english "])
{
NSMutableArray *dd = [[NSMutableArray alloc] initWithArray:[[str stringByReplacingOccurrencesOfString:#"english" withString:#""] componentsSeparatedByString:#" "]];
NSArray *tag = [NSArray aarrayWithObjects:#"er",#"langauge",#"movie",#"actor",#"kate",nil];
NSMutableString *output =[[NSMutableString alloc] init];
NSUInteger tagindex =0;
for (NSString *words in word)
{
if(tagindex >=[tag count])
{
NSLog(#"dad");
break;
}
[output appendFormat:#"<%#>%#<%#>\n", [tag objectAtIndex:tagindex],words,[tag objectAtIndex:tagindex]];
NSLog(#"%#",output);
[output writeToFile:#"/Users/xx/Desktop/homework.txt" atomically:YES encoding:NSASCIIStringEncoding error:NULL];
tagindex++;
now i can able to read only the language and movie (1st line) how i can add second line and tag also
you need write file with c method, maybe the following method can help you
-(void)writeToFile:(NSString *)str:(NSString *) fileName
{
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSString *filePath=[NSString stringWithFormat:#"%#",fileName];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath] == NO){
NSLog(#"file not exist,create it...");
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}else {
NSLog(#"file exist!!!");
}
FILE *file = fopen([filePath UTF8String], [#"ab+" UTF8String]);
if(file != NULL){
fseek(file, 0, SEEK_END);
}
int readSize = [data length];
fwrite((const void *)[data bytes], readSize, 1, file);
fclose(file);
}

App crashed when downloading video

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.

max length of file name

i am using the code below to save an image in the NSDocumentDirectory
-(BOOL)saveImage:(UIImage *)image name:(NSString *)name{
NSString *dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString pathWithComponents:[NSArray arrayWithObjects:dir, name, nil]];
BOOL ok = [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
if (!ok) {
NSLog(#"Error creating file %#", path);
}
else {
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
[myFileHandle writeData:UIImagePNGRepresentation(image)];
[myFileHandle closeFile];
}
return ok;
}
the name is usually the url of where the image was downloaded.
is there a constraint on the length of the file name? you know sometimes urls may be super long...
thank you
Taking a look at the PATH_MAX constant in syslimits.h:91
...
#define PATH_MAX 1024 /* max bytes in pathname */
...
You can test this yourself by doing :
NSLog(#"%i", PATH_MAX);
just to make sure.

Plist file exists in docs dir, but cannot be loaded into an array

The plist has the file suffix .xml and is a normal array of dictionaries.
In the app delegate:
#define docDir [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
-(NSString *)cacheFile:(NSString *)filename sitepath:(NSString *)url {
NSMutableString *retfn=[NSMutableString string];
NSString *mediaUrl=[NSString stringWithFormat:#"%#%#",url,filename];
if(nil != mediaUrl){
NSData* imageData;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
#try {
imageData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:mediaUrl]];
}
#catch (NSException * e) { //error
NSLog(#"%#",#"CacheFile error!");
}
#finally { //save to Documents
[retfn appendFormat:#"%#%#%#",docDir,#"/",filename];
[imageData writeToFile:retfn atomically:YES];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[imageData release];
}
return retfn;
}
In my tableView controller:
#define fname #"myplist.xml"
#define fdir #"http://mysite.com/iPhoneApp/"
- (void)viewDidLoad {
appdel=(EksjoHusAppDelegate *) [[UIApplication sharedApplication] delegate];
NSString *husDataF=[appdel cacheFile:fname sitepath:fdir];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:husDataF];
if (([husDataF length]>0)&&(fileExists)) {
NSMutableArray *lochusData=[[NSMutableArray alloc] initWithContentsOfFile:husDataF];
appdel.husData=lochusData;
[lochusData release];
}
}
initWithContentsOfFile sets lochusData to 0x0. This the part of code I'm asking about, really. The rest is more for completion. cacheFile returns the local filepath or an empty string. All the values are correct, but it just won't load / go into the array.
Feeling dumb. I just don't see the error. Is there something I'm missing?
Answer was, "Check your charset when saving the generated XML, dude" :)