Terminated due to memory error iOS? - ios

I am working on a project where I need to manage videos. I need to rename or delete video. For that we need to hold the video in NSDATA and then manage it.
But I am getting an error message as Terminated due to memory error on below statement.
Edited
NSData *data=[NSData dataWithContentsOfFile:self.path];
if (data){
BOOL success = [data writeToFile:videopath atomically:NO];
}
self.path contains the path of video file. It works in small size video (of 4-10 mins) But it crashes in large size video (bigger than 20-30 mins).
Please advice.

Use this code instead loading the video file to memory, Your code will work with small files but u gonna fail with big files.
if ( [[NSFileManager defaultManager] isReadableFileAtPath:source] ){
[[NSFileManager defaultManager] copyItemAtURL:source toURL:destination error:nil];}

You are maintaing the full video as NSData inside the application. Instead of using a Video file as NSData, copy the video to some where (e.g NSTempoaryDirectoy). You can delete or rename the Old video.

I am not sure what the requirement for you. from your question I understood that you need to rename your video file. for renaming, why we need to go for reading it as NSdata and again writing the same. for Renaming try the below code.
NSFileManager *filemanager = [NSFileManager defaultManager];
if ([filemanager fileExistsAtPath:filePath])
{
NSString *target = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newnameofthefile];
[filemanager moveItemAtPath:filePath toPath:target error:nil];
}
I hope this may help you..

Related

IOS Memory Management - writing video to temp file

I'm creating an app that plays back multiple videos and photos in a snapchat story fashion. I fetch each of these videos data and write it to a temp file in order to play with AVPlayer.
NSString *outputPath = [[NSString alloc] initWithFormat:#"%#%#", NSTemporaryDirectory(), [NSString stringWithFormat:#"output%i.mov", i]];
[data writeToFile:outputPath atomically:YES];
In viewWillDissapear I delete all of these files with:
NSArray* tmpDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:NSTemporaryDirectory() error:NULL];
for (NSString *file in tmpDirectory) {
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:#"%#%#", NSTemporaryDirectory(), file] error:NULL];
}
But when I look at how much memory my app is using, in settings, its around 300 mb. Is there a way to see what is actually taking up all this memory? I would think this is high since I'm not caching anything besides the currentUser data (name, profileImage).
Should I be doing something else to clean the temp files?
But this line is absolutely wrong:
[data writeToFile:outputPath atomically:YES];
The implication is that at some moment — this moment — you are holding an entire video in memory (as data). That is completely incorrect; it should never happen. You should download to a file on disk, and if necessary, write that file to another file; you should never attempt to load the entire video into memory at once.
As #peter mentioned, you can use streaming Video streaming.
Or else If you really want to download video file and store it into the disk space and want to utilize it later part then you should follow apple recommended way i.e NSFileHandle class to optimize your application heap memory while downloading larger files.
NSFileHandle

Lost files in iOS App

I have a app that downloads video and image files from a server. I store these files in folders in my app. I have 3 different places where i store the files:
Caches Directory - Videos + Images downloaded
Application Support Directory - Database
Documents Directory - Videos taken by current user
The code that i use to get paths to these folders is:
+ (NSString *)FilesStoreDirectory
{
NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *path = paths.count ? [(NSURL *)paths.firstObject path] : NSTemporaryDirectory();
NSString *result = [path stringByAppendingPathComponent:#"files"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:result])
{
[fileManager createDirectoryAtPath:result withIntermediateDirectories:YES attributes:nil error:nil];
}
return result;
}
At the logout i remove all these folders and files. The database (sql) is the only file that is not deleted.
My problem is that the size of the app increases while use. I have a example of 4 GB of stored files and after logout it went down to 1.9 GB when it should only be 23 MB + database (small). The way that a check how big is the app is by checking Settings -> Usage.
I am thinking maybe there is a problem with the folder creation and it creates different folders between different runs of the app, but that didn't solve the problem.
I play these video files so i suspect the AVPlayer of caching these files and not letting them go. But that is just a hunch.
Anybody has a idea why this is happening, and how can i get back to 23 MB of app size?
Thanks.
LATER EDIT:
This is the code that i use to remove the folders:
[[NSFileManager defaultManager] removeItemAtPath:[LVCoreDataController FilesStoreDirectory] error:nil];

How to know a file is writing via NSFileManager

I got a problem , How to know the file is accessible ???
For example , the file is writing , but not finish yet.
And I check the file again ,
I use
[[NSFileManager defaultManager] fileExistsAtPath:filePath];
It return true ... but the file is not accessible .
How to determine the file is ready ?
Thanks
Webber
EDIT
Maybe I'm not telling my problem clearly . I mean if you start transport a video file . before transport finish . the video file is not accessible , but you still can get a part of transporting file.
Write Data in async way using GCD concept and once it is completed, the completion handler will be executed.(Where completion of a writing process shall be detected)
The dispatch I/O convenience API lets you perform asynchronous read and write operations on file descriptors. This API supports stream-based semantics for accessing the contents of the file-descriptor.
Method:
void dispatch_write ( dispatch_fd_t fd, dispatch_data_t data, dispatch_queue_t queue, void (^handler)(dispatch_data_t data, int error) );
Ref: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_write
Basically you need to check the attributes of the file and particullary the NSFileBusy attribute:
if ([fileManager fileExistsAtPath:filePath]) {
NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
NSLog(#"File Busy %#", [attributes objectForKey:NSFileBusy]);
}
NSFileCoordinator and NSFilePresenter are created just for that. You may find interesting Advanced iCloud Document Storage video from wwdc that covers the usage of this classes. Building a Document-based App will be great to watch too.
Try to fetch data of file by using following code :
NSURL *url = [NSURL fileURLWithPath:filePath];
NSData *readData = [NSData dataWithContentsOfURL:url];

Save a NSArray to iCloud and retrieve it

I have an app that currently saves a NSMutableArray to a file in the documents directory on the iPad. This is saved by
[residentData writeToFile:filePath atomically:NO];
and is read back in by;
residentData = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
I need to write this file to iCloud, as the data needs to be available across several devices. I have tried the following to create the file in iCloud;
NSData *myFileData = [NSKeyedArchiver archivedDataWithRootObject:residentData];
[fileManager createFileAtPath:[icloudURL path] contents:myFileData attributes:nil];
Which does indeed create a file in the correct place. I am struggling though to understand how to read this file back into my NSMutableArray (residentData). I have tried;
residentData = [NSKeyedUnarchiver unarchiveObjectWithData:myFileData];
But this doesn't decode into the array correctly. Please can someone show me the error of my ways - I suspect a fundamental misunderstanding on my part of NSData is to blame, but any pointers would be welcome.
It finally clicked, my approach was wrong. I don't need to use any of the above. Once I have done the;
[fileManager setUbiquitous:YES itemAtURL:currentPlace destinationURL:icloudURL error:&error];
The system takes care of everything else - i.e. just accessing the file normally with
residentData = [[NSMutableArray alloc] initWithContentsOfURL:icloudURL];
Has worked.

How can I save document files to the SQLite Database in iOS to view them later in the program?

I'm having a problem with the code I'm writing.
I'm writing an iOS program (I'm an iOS rookie) which basically requires me to use quick look framework to view some documents on the iPhone (*.doc, *.ppt, *.pdf etc..) which are stored in the database (Core Data - SQLite, nothing external). I need to add the files somehow, but since iOS isn't really allowing me to browse through its file system I can't find and save the documents i need in database. Which kinda blocks everything else i need to do until I can get those documents from the database. (to set up table views that list the files and the details about the files etc.)
This is for a class project so it doesn't need to be perfect condition, I just need to be able to browse through a few documents while I'm presenting the project. I can add all the documents I'm going to use at one time while I'm coding and I won't need to be able to add any new files when I'm using the program during the presentation. And I don't want it to make it more complicated if i don't have to. Like connecting to an external database with the files already saved in and use a php buffer-page to connect to that database or anything like that. I don't have the necessary server system to execute that php file. I want this operation to be done inside the phone.
The solutions I was able to think of so far:
Grab some random office files from the internet and save them into the database. Then use them later.
Create image scans of some office files and "cheat" by using the scanned image instead of actual documents.
I would really appreciate it if someone can tell me another and much easier way to handle this. Please just keep in mind that while I have a programming background with Java and C#, I'm still an iOS rookie and just barely moving on from scratching the surface. So it is likely that I don't know about something iOS provides by default and I'm just pulling my hair out for nothing.
I think thats it, I hope I didn't forget anything. If you need more details I'm going to be here and I can provide them almost instantly. Thanks everyone in advance for your help.
It sounds like NSFileManager will help you.
If you place your documents into your project tree, they will be available to your app. Use NSFileManager to copy them into the app's Documents folder using something like:
- (void)placeBundleFileInDocuments:(NSString *)filename
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:[[filename lastPathComponent] stringByDeletingPathExtension] ofType:[filename pathExtension]];
NSString *documentsFolderPath = [NSString stringWithFormat:#"%#/", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
NSString *path = [documentsFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#", filename]];
if ([fileManager fileExistsAtPath:path])
return;
NSError *error = nil;
[fileManager copyItemAtPath:bundlePath toPath:path error:&error];
if (error) {
NSLog(#"Unable to copy file (%#).", error.localizedDescription);
}
}
Then, you can use NSFileManager to retrieve details about the files. You might find this method useful:
- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error
I hope this helps!

Resources