loading AVAudioPlayer file URLs from a Plist - objective-c

I'm working with about 50 AVAudioPlayers that each load a separate audio file. The files are fixed and within the app bundle. They are triggered by events later on in the app. Currently I'm hardcoding the creation of each player instance, like so:
//No01
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"audio1" ofType:#"aiff"]];
self.no01Player = [[AVAudioPlayer alloc] initWithContentsOfURL:no01URL error:nil];
no01Player.numberOfLoops = 0;
no01Player.volume = 0;
no01Player.delegate = self;
//No02
NSURL *no02URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"audio2" ofType:#"aiff"]];
self.no02Player = [[AVAudioPlayer alloc] initWithContentsOfURL:no02URL error:nil];
no02Player.numberOfLoops = 0;
no02Player.volume = 0;
no02Player.delegate = self;
//No03 and so on...
Obviously this is labourious and bad coding practice. I'd like to instead have the list of files in a Plist and load these into variables that populate just one example of the above code. I'd like to learn how to be DRY with this but have limited experience of loading data from Plists, arrays, dictionaries, etc.
Any help is appreciated, even if it is to point me in the direction of a relevant tutorial.
Thank you.

You can simply place the audio file names in text file using 'new line' separator. And read the file and store the names in an array. To create the URL take the file names dynamically from array as given below
// Read description from text file
NSBundle *audioBundle = [NSBundle mainBundle];
NSString *audioPath = [audioBundle pathForResource:audioFileNames ofType:#"txt"];
NSString *audioContent = [NSString stringWithContentsOfFile:audioPath encoding:NSUTF8StringEncoding error:nil];
// ===========Make an array using audioContent=============
NSArray *audioFiles = [audioContent componentsSeparatedByString:#"\n"];
Use the array to get file names :
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#",[audioFiles objectAtIndex:audioCount]] ofType:#"aiff"]];
If your file names are like audio1,audio2.. no need of using all these. Just change in URL like :
NSURL *no01URL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"audio%d",audioCount] ofType:#"aiff"]];

OK for anyone else needing to do this, here's what I ended up with:
//Load location data from Plist file into an Array
NSString *path = [[NSBundle mainBundle] pathForResource:#"Audionodes" ofType:#"plist"];
locationArray = [[NSArray alloc] initWithContentsOfFile:path];
// Create AVAudioPlayers for this view
self.audioPlayerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [locationArray count]; i++) {
NSString *filename = [[locationArray objectAtIndex:i] valueForKey:#"filename"];
NSString *filetype = [[locationArray objectAtIndex:i] valueForKey:#"filetype"];
int loops = [[[locationArray objectAtIndex:i] valueForKey:#"loops"] intValue];
NSURL *url = [[NSURL alloc]initFileURLWithPath:[[NSBundle mainBundle] pathForResource:filename ofType:filetype]];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
player.delegate = self;
player.numberOfLoops = loops;
player.volume = 0;
[self.audioPlayerArray addObject:player];
[url release];
[player release];
}
Putting the generated players in audioPlayerArray means I can get at them later.

Related

How can I access to the localized strings inside Settings.bundle in Objective-C?

I need to access to the Settings.bundle and get the descriptions and titles with the localized string.
Use NSLocalizedStringFromTableInBundle function. Create an instance of NSBundle with URL of your bundle and use it as bundle argument. Use “Root” as the table name for tbl argument.
For example:
NSBundle *bundle = [[NSBundle alloc] initWithURL: ...];
NSString *string = NSLocalizedStringFromTableInBundle("SOME_KEY", "Root", bundle, "Comment");
In the end I did it this way:
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"bundle"];
NSBundle *settingsBundle = [NSBundle bundleWithPath:resourcePath];
NSURL *url = [settingsBundle URLForResource:#"Root" withExtension:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfURL:url];
NSArray *preferences = dictionary[#"PreferenceSpecifiers"];
for (NSDictionary *dic in preferences){
NSString *localizedTitle = NSLocalizedStringWithDefaultValue(dic[#"Title"], #"Root", settingsBundle, dic[#"Title"], #"");
}

What causes a "Virtual Memory exhausted" error?

Alright.. Here's the thing.. I am building an app in which when the user taps on download button it downloads a bunch on images (296, to be exact).
In simulator everything works flawless, on my iPhone (4S) on around 100th image it crashes with error:
malloc: * mach_vm_map(size= "some random number") failed (error code= 3)* error: can't allocate region
libBacktraceRecording.dylib: allocate_free_list_pages() -- virtual memory exhausted!
Here's the code I wrote for downloading those images:
-(void)getData
{
NSError *error;
int i;
NSArray *brojLinije = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
NSArray *urlSlike = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"urlSlike" ofType:#"plist"]];
NSArray *pocetno = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"pocetno" ofType:#"plist"]];
NSArray *sortiranje = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *desktopDir = [paths firstObject];
UIImage *image1 = [[UIImage alloc] init];
for (i = 0; i<296; i++) {
NSString *brojLinije1 = [NSString stringWithFormat:#"%#",[brojLinije objectAtIndex:i]];
NSString *pocetno1 = [NSString stringWithFormat: #"%#", [pocetno objectAtIndex:i]];
NSString *tableSort = [NSString stringWithFormat: #"%#", [sortiranje objectAtIndex:i]];
image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png", [urlSlike objectAtIndex:i ] ]]]];
NSData *data1 = [NSData dataWithData:UIImageJPEGRepresentation(image1, 0.1)];
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
NSString *pngFilePath = [NSString stringWithFormat:#"%#%#.jpg",desktopDir,[urlSlike objectAtIndex:i]];
[data1 writeToFile:pngFilePath atomically:YES];
[newManagedObject setValue:brojLinije1 forKey:#"brojLinije"];
[newManagedObject setValue:data1 forKey:#"imageData"];
[newManagedObject setValue:pocetno1 forKey:#"pocetnoStajaliste"];
[newManagedObject setValue:tableSort forKey:#"sort"];
NSLog(#"%d / 296", i);
}
[self.managedObjectContext save:&error];
}
Only thing I know is that the image allocation frequency (too much allocating and no time to automatically release) is making the problem, AND that I have tried every method I know so far, AND I HAVE watched A LOT of "Instruments" app tutorials and only one helped (to find the source of filling virtual memory) but I still can't solve my problem.
You can use a local autorelease pool inside of the loop to immediately release any objects that were created in the body of the loop.
for (i = 0; i<296; i++) {
#autoreleasepool {
// loop body goes here...
}
}
While using SDWebImage framework I encountered a lot of bugs and unanswered crashes from the app. SDWebImage is awesome if the count of images that are about to be downloaded is lower that, let's say 50. Because, when downloading one by one image that are showed in TableViewCell + fast scrolling (fast flicking), the app receives memory warning a couple of times while the TableView is still scrolling (SDWebImage will clear memory ONLY when TableView is slowly scrolling or not scrolling at all) so it crashes the app.
So my only solace with app crashing while downloading 300+ images was simple Apple's method called dispatch_async. More about it here.
And this is how I solved my problem (I just had to move everything from my original -(void)getdata method to dispatch_async block. DONE!
So now it looks like this:
-(void)getData {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Downloading Started");
slike = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"slike" ofType: #"plist"]];
brojevi = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"linije" ofType:#"plist"]];
pocetnaStajalista = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"pocetno" ofType:#"plist"]];
sort = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"sort" ofType:#"plist"]];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Linija" inManagedObjectContext:self.managedObjectContext];
NSString *brojLinije;
NSString *pocetnoStajaliste;
NSString *sortiranje;
NSData *data;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"filename.png"];
for (int i = 0; i<314; i++) {
NSManagedObject *novaLinija = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
brojLinije = [NSString stringWithFormat:#"%#",brojevi[i]];
pocetnoStajaliste = [NSString stringWithFormat:#"%#",pocetnaStajalista[i]];
data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: #"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%#.png",slike[i]]]];
[data writeToFile:filePath atomically:YES];
sortiranje = [NSString stringWithFormat: #"%#", sort[i]];
[novaLinija setValue:data forKey:#"slikaLinije" ];
[novaLinija setValue:brojLinije forKey:#"brojLinije"];
[novaLinija setValue:pocetnoStajaliste forKey:#"pocetnoStajaliste"];
[novaLinija setValue:sortiranje forKey: #"sort"];
NSLog(#"%d / 314", i+1);
NSError *error;
[self.managedObjectContext save:&error];
} }
Hope this helps others with same problem. Good Luck and Happy Coding!
Used all of your and my suggestions and possible solutions, but, I'm sorry, none worked.
The point in this case, when app needs to download A LOT of photos, you really should use SDWebImageDownloader Class Reference.
I know It's frustrating to change the whole method and to realize the previous method (of downloading photos) is useless, so HERE is the tutorial and example on how to use SDWebImageDownloader Class. Good Luck.

Unable to convert a string to a NSURL

I am trying to turn off WAL in CoreData using this code:
// Code to disable journaling mode
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *urlString = [applicationDocumentsDirectory stringByAppendingPathComponent: #"saori.sqlite"];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSDictionary *options = #{NSSQLitePragmasOption:#{#"journal_mode":#"DELETE"}};
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] init];
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:nil];
This is my NSString that I need to convert to a URL:
/Users/rolfmarsh/Library/Application Support/iPhone Simulator/7.1/Applications/7A614C51-AC51-4F5B-9716-6E3D2F160324/Documents/saori.sqlite
When I use that string in this statement, it generates nil.
NSURL *url = [[NSURL alloc] initWithString:urlString];
I don't see anything wrong with the string. What am I doing wrong?
Read the docs for NSURL. You have a file path and you need to create a file URL from the file path.
NSURL *url = [NSURL fileURLWithPath:urlString];

how to access the files of Nested folders in Skydrive API?

NSArray *arr = [[operation.result objectForKey:#"data"] valueForKey:#"name"];
NSArray *arrId = [[operation.result objectForKey:#"data"] valueForKey:#"id"];
NSArray *folder=[[operation.result objectForKey:#"data"]valueForKey:#"type"];
[dictDocument setObject:arrId forKey:#"ID"];
[dictDocument setObject:arr forKey:#"Name"];
[dictDocument setObject:folder forKey:#"type"];
Arrid===>folder.id,file.id
arr===>filename
folder====>type of file Eg.Folder,audio,video
I can't able to access the files of nested folders??
try like this,and once check in copy bundle identifiers files are added succeessfully or not.
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"vid" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
avPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:fileURL error:nil];
avPlayer.delegate = self;
[avPlayer prepareToPlay];
[avPlayer play];
FOR PLAYING VEDIO
You can use MPMoviePlayerController to play local file.
refer this one for playing vedio file.

How to save data locally in app? [duplicate]

This question already has answers here:
Working with data in iOS Apps (What to choose? NSData, CoreData, sqlite, PList, NSUserDefaults)
(2 answers)
Closed 9 years ago.
I've been struggling with this for ages now and I really need some good help here. :)
I have an app where I'm parsing a quite big JSON into appdelegate's didFinishLaunchingWithOptions.
My Model Objects are:
Tab:
NSString *title
NSMutableArray *categories
Category:
NSString *title
NSMutableArray *items
Item
NSString *title
NSString *description
UIImage *image
I need to save the data locally, cause the parsing takes about 15 seconds every time my app starts. I'm using the SBJSON framework.
Here's my code for parsing:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"json_template" ofType:#"json"];
NSString *contents = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *json = [jsonParser objectWithString: contents];
tabs = [[NSMutableArray alloc] init];
jsonParser = nil;
for (NSString *tab in json)
{
Tab *tabObj = [[Tab alloc] init];
tabObj.title = tab;
NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
for (NSString *key in categoryDict)
{
Category *catObj = [[Category alloc] init];
catObj.name = key;
NSArray *items = [categoryDict objectForKey:key];
for (NSDictionary *dict in items)
{
Item *item = [[Item alloc] init];
item.title = [dict objectForKey: #"title"];
item.desc = [dict objectForKey: #"description"];
item.url = [dict objectForKey: #"url"];
if([dict objectForKey: #"image"] != [NSNull null])
{
NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: #"image"]];
NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];
item.image = [UIImage imageWithData: imageData];
}
else
{
UIImage *image = [UIImage imageNamed: #"standard.png"];
item.image = image;
}
[catObj.items addObject: item];
}
[tabObj.categories addObject: catObj];
}
[tabs addObject: tabObj];
}
What is the best way of doing this? Using Core Data or NSFileManager?
If you have som code example too it will make me very happy.
This is the last thing i need to fix before the app is ready for app store and it just kills me! I can't solve this problem.
If you are working on iOS then you save a file to the Documents folder. On Mac OS X it would be in the Application Support folder. Since you are on iOS, read this answer for how to access the Documents folder.
All of the objects that you want to store should implement NSCoding. The above variables already do. Should you want to store the tabs, categories and items directly they would need to implement NSCoding. Then all you need is to serialize them to a file. When opening you app you can look for this file and get your objects back without parsing.
The code should look something like this (untested and error checking is ommited for brevity):
- (void) saveStateToDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
[fileMan removeItemAtPath:docPath error:&error];
// Create the dictionary with all the stuff you want to store locally
NSDictionary *state = #{ ... };
// There are many ways to write the state to a file. This is the simplest
// but lacks error checking and recovery options.
[NSKeyedArchiver archiveRootObject:state toFile:docPath];
}
- (NSDictionary*) stateFromDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
return [NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
return nil;
}