2012-01-30 12 views
5

Spero che il titolo non sia troppo fuorviante ... :)AudioServicesAddSystemSoundCompletion sotto ARC usando __bridge

ho riprodurre un suono di sistema e aggiungere il SoundCompletion-richiamata ad esso in questo modo:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Mentre « sé »è un semplice NSObject

Nel callback di completamento provo a chiamare la riproduzione di routine di nuovo:

ho dovuto aggiungere il __bridge_transfer e la _ _bridge_retained ai cast, altrimenti ricevo errori, arresti anomali o altri comportamenti imprevisti.

Ma il tutto non funziona nonostante tutto ciò.

Memorizzo i suoni per riprodurli in un NSMutableArray, acquisisco la prima voce dell'array e lo suono, aggiungo il completamento del suono e mi auguro che succeda qualcosa. Ma - con tutto ciò che ha mantenuto trasferimento roba, il NSMutableArray è vuota, in seconda convocazione ...

Ecco il codice:

static void completionCallback (SystemSoundID mySSID, void *myself) { 

    NSLog(@"Audio callback"); 

    AudioServicesRemoveSystemSoundCompletion (mySSID); 
    AudioServicesDisposeSystemSoundID(mySSID); 

    [(__bridge_transfer Speaker *)myself speakCharacter]; 

    CFRelease(myself); // I heard I need this? 

} 

-(void)speakCharacter{ 

    if([sounds count] > 0){ 

     NSString *soundToPlay = [sounds objectAtIndex:0]; 
     [sounds removeObjectAtIndex:0]; 
     NSLog(@"TxtToSpeak %@", soundToPlay); 
     CFURLRef  soundFileURLRef; 
     NSURL *path = [[NSBundle mainBundle] URLForResource:[soundToPlay uppercaseString] withExtension:@"aif"]; 
     soundFileURLRef = (__bridge CFURLRef)path; 
     SystemSoundID soundID; 
     AudioServicesCreateSystemSoundID(soundFileURLRef, &soundID); 
     AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 
     AudioServicesPlaySystemSound (soundID); 
    } 
} 

[EDIT] - rispondere alla mia domanda OWN:

Sempre bello trovarlo da solo :)

Alla fine, ero quasi arrivato.

La chiamata per impostare la richiamata è la seguente:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Poi, nella funzione di callback, faccio questo:

myClass *theClass = (__bridge myClass *)myself; 
    CFRelease(myself); 
    [theClass playNextSound]; // The routine that plays the sounds 

e funziona ...

+0

Grazie per la risposta, mi ha davvero aiutato! È quasi mancato però, dato che la domanda non ha risposta - ti è permesso aggiungere una risposta alla tua stessa domanda? O posso aggiungerlo indicando i tuoi commenti? Saluti v molto comunque] – davidfrancis

risposta

8

Non ho potuto rispondere alla mia domanda dato che ero troppo veloce per StackOverflow - quindi, per rendere tutto completo, aggiungo di nuovo la risposta :)

Si scopre che ero quasi arrivato.

La chiamata per impostare la richiamata è la seguente:

AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, completionCallback, (__bridge_retained void *)self); 

Poi, nella funzione di callback, faccio questo:

myClass *theClass = (__bridge myClass *)myself; 
CFRelease(myself); 
[theClass playNextSound]; // The routine that plays the sounds 

e funziona ...

+0

C'è un motivo per cui non puoi semplicemente usare __bridge? Ottengo crash che accedono all'oggetto dopo con questo metodo. –

+0

Funziona per me. @AlastairStuart Penso che il punto sia quando passi oggetto a 'AudioServicesAddSystemSoundCompletion' che esegui __bridge_retained che aumenterà il retainCount di 1. __bridge non garantisce il trasferimento della proprietà, quindi il contatore rimarrà lo stesso in callback. CFRelease quindi diminuirà retainCount di 1 e infine cancella l'oggetto. – Andy

+0

Il CFR non dovrebbe essere su "theClass" rispetto a "me stesso"? – shim

4

Per chi ha bisogno di un piccolo aiuto in più ... Ho la risposta di Swissdude per lavorare in un controller di visualizzazione comune come tale:

nota: (non è possibile utilizzare CFRelease (me))

.h

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

@interface MYVIEWCONTROLLERNAME : UIViewController 

@property SystemSoundID mySentenceAudio; 

@end 

.m

#import "MYVIEWCONTROLLERNAME.h" 

@interface MYVIEWCONTROLLERNAME() 
{ 
    int myLetterCount; 
    int myWordLength; 
} 
@end 

@implementation MYVIEWCONTROLLERNAME 

@synthesize mySentenceAudio; 


    #pragma mark - Click Action 

- (IBAction)SpellButtonPress:(UIButton *)sender { 
    [self AudioDataAndPlayerLoader]; 
    myLetterCount = 0; 
} 

# pragma mark - Audio Data 

-(void) AudioDataAndPlayerLoader { 

    NSString*myWord = @"apple"; 
    myWordLength = myWord.length; 
    NSArray*wordArray= [self stringToLetterArray:myWord]; 

    if (myWordLength > myLetterCount) { 
     NSString* myLetter = [wordArray objectAtIndex:myLetterCount]; 
     [self playMySound:myLetter]; 
    } 
} 

- (NSArray*)stringToLetterArray:(NSString*)string { 
    NSUInteger characterCount = [string length]; 
    NSMutableArray *temparray = [NSMutableArray arrayWithCapacity:[string length]]; 
    for (int i = 0; i<characterCount; i++) 
    { 
     [temparray addObject:[string substringWithRange:NSMakeRange (i,1)]]; 
    } 
    return [temparray copy]; 
} 

#pragma mark - Audio Loop 

- (void) myAudioLoopCheck { 
    myLetterCount++; 
    NSLog(@"Audio Looped"); 
    if (myWordLength > myLetterCount) { 
     [self performSelector:@selector(AudioDataAndPlayerLoader) withObject:nil afterDelay:.2]; 
    } 
    else { 
     NSLog(@"Done"); 
     myLetterCount = 0; 
    } 
} 

#pragma mark - Audio Player 

- (void) playMySound: (NSString*)soundTitle{ 

    NSString* SOUNDPATH = [[NSBundle mainBundle] 
          pathForResource:soundTitle 
          ofType:@"m4a" 
          inDirectory:@"audio/abc/"]; 
    if (SOUNDPATH != nil) { 

     CFURLRef baseURL = (__bridge_retained CFURLRef) [[NSURL alloc] initFileURLWithPath:SOUNDPATH]; 
     AudioServicesCreateSystemSoundID (baseURL, &mySentenceAudio); 

     AudioServicesPlaySystemSound(mySentenceAudio); 
     CFRelease(baseURL); 

     AudioServicesAddSystemSoundCompletion (mySentenceAudio,NULL,NULL,theAudioServicesSystemSoundCompletionProc,(__bridge void*)self); 
    } 
    else { 
    } 
} 

#pragma mark - Audio Player Callback 

static void theAudioServicesSystemSoundCompletionProc (SystemSoundID mySentenceAudio, void *myself) { 
    NSLog(@"Audio callback"); 
    AudioServicesRemoveSystemSoundCompletion (mySentenceAudio); 
    AudioServicesDisposeSystemSoundID(mySentenceAudio); 

    MYVIEWCONTROLLERNAME *theClass = (__bridge MYVIEWCONTROLLERNAME *)myself; 
    [theClass myAudioLoopCheck]; 
} 

// life cycle code... 
Problemi correlati