AudioServicesAddSystemSoundCompletion в ARC с использованием __bridge

Надеюсь, название не слишком вводит в заблуждение... :)

Я воспроизвожу системный звук и добавляю к нему SoundCompletion-Callback следующим образом:

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

Принимая во внимание, что «self» — это простой NSObject

В обратном вызове завершения я снова пытаюсь вызвать подпрограмму воспроизведения:

Мне пришлось добавить __bridge_transfer и __bridge_retained к приведениям, иначе я получаю ошибки, сбои или другое неожиданное поведение.

Но все это не работает, несмотря на все это.

Я сохраняю звуки для воспроизведения в NSMutableArray, беру первую запись массива и проигрываю ее, добавляю завершение звука и надеюсь, что все произойдет. Но со всем этим сохраненным переносом NSMutableArray пуст при втором вызове...

Вот код:

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);
    }
}

[РЕДАКТИРОВАТЬ] - ОТВЕТ НА МОЙ СОБСТВЕННЫЙ ВОПРОС:

Всегда приятно узнать это самому :)

Оказывается, я был почти там.

Вызов для настройки обратного вызова выглядит следующим образом:

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

Затем в callback-функции я делаю так:

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

И это работает...


person Swissdude    schedule 30.01.2012    source источник
comment
Спасибо за ответ, очень помог мне! Однако почти пропустил это, так как вопрос остается без ответа - вы можете добавить ответ на свой вопрос? Или я могу добавить его, указывая на ваши комментарии? Приветствую вас в любом случае;]   -  person davidfrancis    schedule 15.03.2012


Ответы (2)


Я не мог ответить на свой вопрос, так как я был слишком быстр для StackOverflow, поэтому, чтобы завершить это, я снова добавляю ответ :)

Оказывается, я был почти там.

Вызов для настройки обратного вызова выглядит следующим образом:

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

Затем в callback-функции я делаю так:

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

И это работает...

person Swissdude    schedule 21.03.2012
comment
Есть ли причина, по которой вы не можете просто использовать __bridge? Я получаю сбои при доступе к объекту после этого метода. - person Alastair Stuart; 12.03.2013
comment
Работает на меня. @AlastairStuart Я думаю, что когда вы передаете объект AudioServicesAddSystemSoundCompletion, вы выполняете __bridge_retained, что увеличивает keepCount на 1. __bridge гарантирует отсутствие передачи права собственности, поэтому счетчик останется прежним в обратном вызове. Затем CFRelease уменьшит RetainCount на 1 и в конечном итоге удалит объект. - person Ben Affleck; 21.06.2014
comment
Разве CFRRelease не будет на «theClass», а не на «myself»? - person shim; 02.11.2015

Для тех, кому нужна небольшая дополнительная помощь... Я получил ответ Swissdude для работы в обычном контроллере представления как таковом:

примечание: (вы не можете использовать CFRelease (я))

.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...
person MGM    schedule 07.02.2014