iCulture forum | iPhone, iPad,  iPod touch, Apple TV en iOS

iCulture forum | iPhone, iPad, iPod touch, Apple TV en iOS (https://forum.iculture.nl/)
-   Ontwikkelen voor iOS (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/)
-   -   Audio/sound .plist cellforrow (https://forum.iculture.nl/f133/development/f58/ontwikkelen-voor-ios/98588-audio-sound-plist-cellforrow.html)

gobelz 04-09-11 21:15

Audio/sound .plist cellforrow
 
Beste,

Ik weet niet of er een mogelijkheid is om een audio/sound van welk bestand dan ook (mp3, wav, etc.) af te spelen uit een .plist file in combinatie met een geselecteerde Row.

v.b.
<key>name<key>
<string>Eddie<string>
<key>sound<key>
<string>eddie.mp3<string>

Ik gebruik een tableview om de namen te tonen uit een .plist, bij een selectie van een van de namen gaat het naar een detailview met daarbij extra info. Op de achtergrond zou die een sound/audio moeten afspelen die bij die naam hoort.

Ik wil graag weten of dit daadwerkelijk kan, heb op internet gekeken maar dat levert tot nu toe niks op.

p.s. Het lukt mij wel om foto's te tonen met hetzelfde voorbeeld.

groeten!

Whacko 05-09-11 13:54

Ja hoor dat kan. Als je gewoon de bestandsnaam hebt kun je die met AVAudioPlayer afspelen.

gobelz 23-09-11 20:17

Hoe kan je dat combineren met een .plist file waar de audio file staat 'geregistreerd'. Ik heb hier naar gekeken maar het lijkt net of ik afdwaal.

Wat het ongeveer zou moeten doen is met:
.plist
audio file
tableview

Bij het klikken op een cell, dus didselectrow en er wordt genavigeerd naar de detailview pagina. Hierin moet er bij het geselecteerde de audio op de 'achtergrond' afspelen.

Ik weet dat je met AVAudio aanstuurt om audio files af te spelen. Dit lukt mij met code en een audio bestand die ik op een normale manier afspeel zonder plist.

Het is mij niet gelukt om door de gekozen cell een audio file af te laten spelen door middel van een plist.

Komt dit bekend voor? Kan iemand mij ondersteunen?

mvg,

gobelz 24-09-11 23:57

iemand een idee?

Dit is wat ik nu heb;

Code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
       
        DetailViewController *detailController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:[NSBundle mainBundle]];
        [self.navigationController pushViewController:detailController animated:YES];
       
   
        detailController.titel.text = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
       
        detailController.omschrijving.text = [[names objectAtIndex:indexPath.row] objectForKey:@"description"];
       
        detailController.title = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
   
    NSString *filename = [[names objectAtIndex:indexPath.row] objectForKey:@"sound"];
    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"wav"];
       
    AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL]; 
    theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
   
    [newAudio release]; // release the audio safely
   
    theAudio.delegate = self;
    [theAudio prepareToPlay];
    [theAudio setNumberOfLoops:0];
    [theAudio play];
   
        [detailController release];
}

Iemand een idee? Dit zo me onwijs helpen!

DJ14 25-09-11 11:58

Check of alle waarden kloppen die je gebruikt (bijv. de variabelen "file" en "path" NSLog'gen). Verder is de code die je gaf nogal slordig, hier een verbetering:

Code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

        //Eerst het audio bestand starten of eerst de nieuwe viewcontroller pushen maakt niet veel uit


        //Zorg alsjeblieft eerst ervoor dat de property's van detailController geset worden, voordat hij gepusht wordt   
            DetailViewController *detailController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:[NSBundle mainBundle]];
        detailController.titel.text = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
        detailController.omschrijving.text = [[names objectAtIndex:indexPath.row] objectForKey:@"description"];
        detailController.title = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
        [self.navigationController pushViewController:detailController animated:YES];
        [detailController release];

        NSString *filename = [[names objectAtIndex:indexPath.row] objectForKey:@"sound"];
        NSLog(@"Filename equals: %@", filename);
        NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"wav"];
        NSLog(@"Path equals: %@", path);
        //Check of de NSLog outputs kloppen!!!!


        NSError *error = nil;       
        AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; 
        if(error){
        NSLog(@"Error occurred while preparing AVAudioPlayer instance:%@", [error userInfo]");
        }
        theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
   
        [newAudio release]; // release the audio safely
   
        theAudio.delegate = self;
        [theAudio prepareToPlay];
        [theAudio setNumberOfLoops:0];
        [theAudio play];

}


gobelz 25-09-11 18:04

Citaat:

Oorspronkelijk geplaatst door DJ14 (Bericht 707980)
Check of alle waarden kloppen die je gebruikt (bijv. de variabelen "file" en "path" NSLog'gen). Verder is de code die je gaf nogal slordig, hier een verbetering:

Code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

        //Eerst het audio bestand starten of eerst de nieuwe viewcontroller pushen maakt niet veel uit


        //Zorg alsjeblieft eerst ervoor dat de property's van detailController geset worden, voordat hij gepusht wordt   
            DetailViewController *detailController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:[NSBundle mainBundle]];
        detailController.titel.text = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
        detailController.omschrijving.text = [[names objectAtIndex:indexPath.row] objectForKey:@"description"];
        detailController.title = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
        [self.navigationController pushViewController:detailController animated:YES];
        [detailController release];

        NSString *filename = [[names objectAtIndex:indexPath.row] objectForKey:@"sound"];
        NSLog(@"Filename equals: %@", filename);
        NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"wav"];
        NSLog(@"Path equals: %@", path);
        //Check of de NSLog outputs kloppen!!!!


        NSError *error = nil;       
        AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; 
        if(error){
        NSLog(@"Error occurred while preparing AVAudioPlayer instance:%@", [error userInfo]");
        }
        theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
   
        [newAudio release]; // release the audio safely
   
        theAudio.delegate = self;
        [theAudio prepareToPlay];
        [theAudio setNumberOfLoops:0];
        [theAudio play];

}



Kan je mij vertellen waarom het nodig is om er eerst voor te zorgen dat het eerst geest wordt vervolgens gepusht? Ik wist hier namelijk niet van af.

Ik heb vervolgens de code geïmplementeerd in mijn huidige. Heb even de variabelen afgestemd en geprobeerd. De volgende foutmelding komt aan de orde;

Code:

2011-09-25 17:00:00.462 Ilahi[9480:c203] Filename equals: Ma.mp3
2011-09-25 17:00:00.464 Ilahi[9480:c203] Path equals: (null)
2011-09-25 17:00:00.472 Ilahi[9480:c203] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'
*** Call stack at first throw:
(
        0  CoreFoundation                      0x00ef85a9 __exceptionPreprocess + 185
        1  libobjc.A.dylib                    0x0104c313 objc_exception_throw + 44
        2  CoreFoundation                      0x00eb0ef8 +[NSException raise:format:arguments:] + 136
        3  CoreFoundation                      0x00eb0e6a +[NSException raise:format:] + 58
        4  Foundation                          0x008eeab6 -[NSURL(NSURL) initFileURLWithPath:] + 90
        5  Foundation                          0x008eea44 +[NSURL(NSURL) fileURLWithPath:] + 72
        6  Ilahi                              0x00003283 -[RootViewController tableView:didSelectRowAtIndexPath:] + 1283
        7  UIKit                              0x001c1b68 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
        8  UIKit                              0x001b7b05 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 219
        9  Foundation                          0x008d179e __NSFireDelayedPerform + 441
        10  CoreFoundation                      0x00ed98c3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
        11  CoreFoundation                      0x00edae74 __CFRunLoopDoTimer + 1220
        12  CoreFoundation                      0x00e372c9 __CFRunLoopRun + 1817
        13  CoreFoundation                      0x00e36840 CFRunLoopRunSpecific + 208
        14  CoreFoundation                      0x00e36761 CFRunLoopRunInMode + 97
        15  GraphicsServices                    0x02cb31c4 GSEventRunModal + 217
        16  GraphicsServices                    0x02cb3289 GSEventRun + 115
        17  UIKit                              0x00158c93 UIApplicationMain + 1160
        18  Ilahi                              0x00002139 main + 121
        19  Ilahi                              0x000020b5 start + 53
        20  ???                                0x00000001 0x0 + 1
)
terminate called throwing an exception

Waarom zou het bij Path equals: deze naar null verwijzen? Terwijl ik het toch ergens naar verwijs;

NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];

Er is toch een mogelijkheid om mp3 met AVFoundation.

DJ14 25-09-11 19:08

Citaat:

Oorspronkelijk geplaatst door gobelz (Bericht 708032)
Kan je mij vertellen waarom het nodig is om er eerst voor te zorgen dat het eerst geest wordt vervolgens gepusht? Ik wist hier namelijk niet van af.

Zodra jij de call [self.navigationController pushViewController: detailController animated:YES] doet, geef je de ownership van detailController uit handen. Dat betekent dat jij er niets meer over te zeggen hebt, omdat de detailController nu in handen is van de navigationController. En als je er niets meer over te zeggen hebt, kun je ook geen properties meer setten. Zorg dus altijd eerst dat je properties set, en daarna de detailController instance op de navigation stack pusht.

De error vertelt ons dat er gezocht wordt naar een file, maar dat deze niet is gevonden. Dat komt omdat je filepath variabele onjuist is. In je code zoek je namelijk naar het bestand "Ma.mp3.wav" (dubbele extensie doordat de variabele filename de extensie ook bevat). Zorg dat je dat in orde hebt, dus check hoe je bestand heet (Ma.mp3 of Ma.wav) en zorg dat filename alleen de naam van het bestand bevat zonder de extensie.

Overigens kun je dat probleem met dubbele extensie ook oplossen door de volgende code te gebruiken, maar dan moet je zeker weten dat het bestand een wav extensie heeft:

Code:

fileName = [fileName stringByDeletingPathExtension];

gobelz 25-09-11 23:15

Exact! Gedaan wat er gevraagd wordt. In mijn .plist heb ik de filename gewijzigd in <>Ma<> zonder de extensie .mp3

Vervolgens bij de simulator krijg ik te maken met een vastloper zonder enige reden volgens mij, zie;

Code:

2011-09-25 22:12:42.905 Ilahi[9787:c203] Filename equals: Ma
2011-09-25 22:12:42.907 Ilahi[9787:c203] Path equals: /Users/LionJack/Library/Application Support/iPhone Simulator/4.3.2/Applications/B7A53018-8B05-4933-82AB-1CD933A358B2/Ilahi.app/Ma.mp3

Daar gaat het inderdaad naar de juiste zoeken, maar bij het selecteren van de cell loopt de simulator vast met bovenstaand melding.

DJ14 25-09-11 23:45

Die meldingen uit de console die je hier post zijn niet zomaar geproduceerd door de debugger, maar die had ik er in je code bijgezet (google maar op de NSLog functie). Vreemd dat de console geen details geeft over de crash. Doorloop zelf nog even je didSelectRowAtIndexPath functie en check of je nergens fouten maakt in memory management e.d. Anders vrees ik dat je je hele didSelectRowAtIndexPath functie hier moet posten, zonder dingen weg te laten.

gobelz 25-09-11 23:58

Citaat:

Oorspronkelijk geplaatst door DJ14 (Bericht 708090)
Die meldingen uit de console die je hier post zijn niet zomaar geproduceerd door de debugger, maar die had ik er in je code bijgezet (google maar op de NSLog functie). Vreemd dat de console geen details geeft over de crash. Doorloop zelf nog even je didSelectRowAtIndexPath functie en check of je nergens fouten maakt in memory management e.d. Anders vrees ik dat je je hele didSelectRowAtIndexPath functie hier moet posten, zonder dingen weg te laten.

Is er een limiet qua grootte van een mp3 bestand? Welke extensie komt het best uit de test om audio af te spelen? Heb jij hier nog tips voor?

Ik ben nu de didselectrow aan het doornemen inderdaad, ik post morgen wat in de discussie.

Als je kijkt;

Code:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   
    //Eerst het audio bestand starten of eerst de nieuwe viewcontroller pushen maakt niet veel uit
   
   
    //Zorg alsjeblieft eerst ervoor dat de property's van detailController geset worden, voordat hij gepusht wordt   
    DetailViewController *detailController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:[NSBundle mainBundle]];
        detailController.titel.text = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
        detailController.omschrijving.text = [[names objectAtIndex:indexPath.row] objectForKey:@"description"];
        detailController.title = [[names objectAtIndex:indexPath.row] objectForKey:@"name"];
    [self.navigationController pushViewController:detailController animated:YES];
    [detailController release];
   
    NSString *filename = [[names objectAtIndex:indexPath.row] objectForKey:@"sound"];
    NSLog(@"Filename equals: %@", filename);
    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];
    NSLog(@"Path equals: %@", path);
    //Check of de NSLog outputs kloppen!!!!
   
   
   
    NSError *error = nil;       
    AVAudioPlayer *newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; 
    if(error){
        NSLog(@"Error occurred while preparing AVAudioPlayer instance:%@", [error userInfo]);
              }
              theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
             
              [newAudio release]; // release the audio safely
             
              theAudio.delegate = self;
              [theAudio prepareToPlay];
              [theAudio setNumberOfLoops:0];
              [theAudio play];
}

dan is dit mijn didselectrow.

Mijn plist;
Code:

<key>sound</key>
<string>Ma</string>

Is het ook zo dat ik een String moet gebruiken?

gobelz 26-09-11 23:06

Heb er nog even naar gekeken maar kom er niet uit. Ik vul het even aan met code hoe ik mijn .plist ophaal.

Code:

- (void)viewDidLoad {
   
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Ila" ofType:@"plist"];
       
        NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithContentsOfFile:path];
       
        self.names = tmpArray;
   
        [tmpArray release];

In mijn RootView heb ik;
Code:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface RootViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, AVAudioPlayerDelegate> {
   
    NSArray    *names;
   
    AVAudioPlayer *theAudio;
       
}

@property (nonatomic, retain) NSArray *names;

In mijn DetailView wordt de AVFoundation ook geimport en de delegate wordt ingevoerd.

Ik zie niet wat er mis gaat en wat ik over het hoofd heb gezien. Iemand een suggestie? oplossing?

gobelz 28-09-11 22:36

Iemand een idee? Ik ben er nog steeds niet uit...

DJ14 28-09-11 23:06

De variabelen "theAudio" en "names" worden nergens gealloceerd en geinitieerd. Doe dit eerst eens direct na "[super viewDidLoad]" in je viewDidLoad method. ([super viewDidLoad] dient de eerste regel code in je viewDidLoad method te zijn). Die hele tmpArray kun je trouwens weglaten, gebruik daarvoor gewoon direct de names array.

gobelz 29-09-11 21:43

Citaat:

Oorspronkelijk geplaatst door DJ14 (Bericht 708609)
De variabelen "theAudio" en "names" worden nergens gealloceerd en geinitieerd. Doe dit eerst eens direct na "[super viewDidLoad]" in je viewDidLoad method. ([super viewDidLoad] dient de eerste regel code in je viewDidLoad method te zijn). Die hele tmpArray kun je trouwens weglaten, gebruik daarvoor gewoon direct de names array.

De 'theAudio' wordt toch geïnitieerd en gealloceerd in didselectrow? en names wordt in viewdidload geïnitieerd en gealloceerd?

Verbeter mij als ik het verkeerd heb...

ps. dit wordt helaas heel erg langdradig

DJ14 29-09-11 22:17

Citaat:

Oorspronkelijk geplaatst door gobelz (Bericht 708752)
De 'theAudio' wordt toch geïnitieerd en gealloceerd in didselectrow?

Neen, in didSelectRow alloceer je en initieer je "newAudio", en wijs je de inhoud van deze variabele vervolgens toe aan "theAudio". Maar theAudio zie ik in je code nergens gealloceerd en geinitieerd worden, dus wijs je een variabele met inhoud toe aan een variabele die geen plek in het geheugen heeft gekregen, dus ook geen inhoud kan hebben (nil).


Citaat:

Oorspronkelijk geplaatst door gobelz (Bericht 708752)
en names wordt in viewdidload geïnitieerd en gealloceerd?

Neen (zelfde verhaal), je alloceert en initieert "tmpArray" wel, maar "names" niet..

JornZ 30-09-11 15:42

@DJ14: Bij names gaat het wel goed omdat hij de setter gebruikt doormiddel van self.names.

@gobelz:
Ik zou theAudio ook een property maken van je RootViewController, zodat je makkelijk de getter en setter method kan synthesizen in de .m file. Vergeet dit dus niet. Voor names zou je hetzelfde gedaan moeten hebben. Als je vervolgens de setter gebruikt om newAudio aan theAudio toe te wijzen is de code correct. Dus:
Code:

self.theAudio = newAudio;
of
Code:

[self setTheAudio:newAudio];
In jouw eigen code doe je het volgende:
Code:

theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
     
              [newAudio release]; // release the audio safely
             
              theAudio.delegate = self;
              [theAudio prepareToPlay];
              [theAudio setNumberOfLoops:0];
              [theAudio play];

Wat hier fout gaat is dat je door de statement theAudio = newAudio alleen maar de pointer naar het object in het geheugen overneemt in theAudio en juist niet het object retained (zoals het commentaar suggereert), het laatste gebeurt wel als je de setter method gebruikt voor theAudio zoals ik net beschreef. De consequentie van het vervolgens releasen van newAudio is dat ook theAudio naar een stuk geheugen verwijst wat mogelijk al gereleased is en je app kan crashen op de statements die iets met theAudio willen doen. Je kan de code dus ook repareren door voor de release van newAudio een retain te doen voor theAudio, alleen is dat in mijn ogen geen nette code en is het veel beter jezelf aan te leren de setters en getters te gebruiken.

gobelz 30-09-11 22:18

Bedankt voor de hulp, DJ14.

Heb het voor nu opgelost. Misschien kan ik de code nog optimaliseren maar voor nu doet ie wat ik wil.

Zie;
Code:

NSString *filename = [[nameSection objectAtIndex:row] objectForKey:@"sound"];
    NSLog(@"Filename equals: %@", filename);
    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];
    NSLog(@"Path equals: %@", path);
    //Check of de NSLog outputs kloppen!!!!
   
        NSError *error;
        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
       
        audioPlayer.delegate = self;
    [audioPlayer prepareToPlay];
    [audioPlayer setNumberOfLoops:0];
    [audioPlayer play];

En vervolgens als er teruggekeerd wordt naar de tableview/rootview wordt uiteraard de audio stopgezet.

Code:

-(void)viewWillAppear:(BOOL)animated {
    [audioPlayer stop];
}

Als men nog opmerkingen heeft, graag..

Groet,

JornZ 01-10-11 13:09

Ik kan natuurlijk niet je volledige code zien, maar ik denk dat je hier wel een memory leak hebt gemaakt. Tenzij je nog ergens audioPlayer released voordat er een volgende keer de didselectrow method wordt gebruikt?

Ik zal even kort uitleggen waarom;
Zo te zien is audioPlayer een instance variabele of misschien zelfs een property van je RootViewController (waarin de tableview staat). Omdat je geen setter method gebruikt voor audioPlayer maar directe toewijzing middels:
Code:

audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
verlies je elke keer de pointer naar het vorige object wanneer je een volgende keer een rij selecteert in je tabel. Dus zou je in de didselectrow eerst audioPlayer kunnen releasen als deze niet nil is, of in ieder geval ergens voordat je opnieuw geheugen alloceert in didselectrow. Maar (zie ook mijn vorige post) dat is in principe geen nette code en ook onnodig in objective-C, daarom hebben ze nou net de setters en getters via synthesize geïmplementeerd. Ik raad je ten zeerste aan om een andere stijl te gaan hanteren, zodat je geen memory leaks creëert. Werk met properties en synthesize de methods en gebruik de setter om nieuwe objecten toe te wijzen, dan weet je zeker dat een oud object altijd wordt gereleased en geen lek wordt.

Voor dit stukje code raad ik je aan om van audioPlayer dus een property te maken en vervolgens de setter method te gebruiken in didselectrow.
Code:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface RootViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, AVAudioPlayerDelegate> {
   
    NSArray    *names;   
    AVAudioPlayer *audioPlayer;
       
}

@property (nonatomic, retain) NSArray *names;
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;

en

Code:


synthesize audioPlayer;

...
...


NSString *filename = [[nameSection objectAtIndex:row] objectForKey:@"sound"];
    NSLog(@"Filename equals: %@", filename);
    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];
    NSLog(@"Path equals: %@", path);
    //Check of de NSLog outputs kloppen!!!!
   
    NSError *error;
    AVAudioPlayer *newAVAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];   
    [self setAudioPlayer:newAVAudioPlayer];
    [newAVAudioPlayer release];

    audioPlayer.delegate = self;
    [audioPlayer prepareToPlay];
    [audioPlayer setNumberOfLoops:0];
    [audioPlayer play];


gobelz 01-10-11 13:23

Citaat:

Oorspronkelijk geplaatst door JornZ (Bericht 709113)
Ik kan natuurlijk niet je volledige code zien, maar ik denk dat je hier wel een memory leak hebt gemaakt. Tenzij je nog ergens audioPlayer released voordat er een volgende keer de didselectrow method wordt gebruikt?

Ik zal even kort uitleggen waarom;
Zo te zien is audioPlayer een instance variabele of misschien zelfs een property van je RootViewController (waarin de tableview staat). Omdat je geen setter method gebruikt voor audioPlayer maar directe toewijzing middels:
Code:

audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
verlies je elke keer de pointer naar het vorige object wanneer je een volgende keer een rij selecteert in je tabel. Dus zou je in de didselectrow eerst audioPlayer kunnen releasen als deze niet nil is, of in ieder geval ergens voordat je opnieuw geheugen alloceert in didselectrow. Maar (zie ook mijn vorige post) dat is in principe geen nette code en ook onnodig in objective-C, daarom hebben ze nou net de setters en getters via synthesize geïmplementeerd. Ik raad je ten zeerste aan om een andere stijl te gaan hanteren, zodat je geen memory leaks creëert. Werk met properties en synthesize de methods en gebruik de setter om nieuwe objecten toe te wijzen, dan weet je zeker dat een oud object altijd wordt gereleased en geen lek wordt.

Voor dit stukje code raad ik je aan om van audioPlayer dus een property te maken en vervolgens de setter method te gebruiken in didselectrow.
Code:

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface RootViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, AVAudioPlayerDelegate> {
   
    NSArray    *names;   
    AVAudioPlayer *audioPlayer;
       
}

@property (nonatomic, retain) NSArray *names;
@property (nonatomic, retain) AVAudioPlayer *audioPlayer;

en

Code:


synthesize audioPlayer;

...
...


NSString *filename = [[nameSection objectAtIndex:row] objectForKey:@"sound"];
    NSLog(@"Filename equals: %@", filename);
    NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];
    NSLog(@"Path equals: %@", path);
    //Check of de NSLog outputs kloppen!!!!
   
    NSError *error;
    AVAudioPlayer *newAVAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];   
    [self setAudioPlayer:newAVAudioPlayer];
    [newAVAudioPlayer release];

    audioPlayer.delegate = self;
    [audioPlayer prepareToPlay];
    [audioPlayer setNumberOfLoops:0];
    [audioPlayer play];


Heb de tip meegenomen in mijn project, je uitleg is overigens duidelijk. Ook de setters en de getters natuurlijk. Ik wil nog wel kijken naar de memory management of er leaks zijn.

Ik gebruik nu de extensie .mp3 in mijn project maar dit is gemiddeld een bestand van 3,5mb. Welk ander extensie kan ik het best gebruiken voor het afspelen van audio? En uiteraard de huidige grootte van een bestand reduceren

JornZ 01-10-11 13:44

Volgens mij is mp3 wel de beste optie die je hebt. Voor zover ik weet is de iPhone/iPad/iPod hardware ook geoptimaliseerd voor dit formaat. De bestandsgrootte is te beïnvloeden doormiddel van de bitrate van je MP3's, kies je een lagere bitrate of VBR (variabele bitrate, afhankelijk van de dynamiek van de muziek worden er meer of minder bits gebruikt) dan zal je bestand kleiner worden maar mogelijk de kwaliteit van het geluid afnemen.


Alle tijden zijn GMT +2. Het is nu 18:39.