2012-01-30 11 views
5

Tôi hy vọng danh hiệu không phải là quá sai lầm ... :)AudioServicesAddSystemSoundCompletion dưới ARC sử dụng __bridge

tôi chơi một hệ thống âm thanh và thêm SoundCompletion-Callback để nó như vậy:

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

Trong khi « tự »là một NSObject đơn giản

Trong callback hoàn thành tôi cố gắng gọi cho thói quen chơi một lần nữa:

tôi phải thêm __bridge_transfer và _ _bridge_retained cho các phôi, nếu không tôi nhận được lỗi, sự cố hoặc hành vi không mong muốn khác.

Nhưng toàn bộ mọi thứ không hoạt động mặc dù vậy.

Tôi lưu trữ âm thanh để phát trong NSMutableArray, lấy mục nhập đầu tiên của mảng và phát, thêm âm thanh hoàn thành và hy vọng mọi thứ xảy ra. Nhưng - với tất cả những gì giữ lại chuyển công cụ, các NSMutableArray là trống trên cuộc gọi thứ hai ...

Dưới đây là các mã:

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] - Trả lời câu hỏi của riêng tôi:

Luôn luôn tốt đẹp để tìm thấy nó ra bản thân mình :)

Hóa ra, tôi đã gần như ở đó.

Cuộc gọi thành lập gọi lại như sau:

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

Sau đó, trong khi gọi lại chức năng, tôi làm điều này:

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

Và nó hoạt động ...

+0

Cảm ơn câu trả lời đã thực sự giúp tôi! Gần như đã bỏ lỡ nó, vì câu hỏi xuất hiện chưa được trả lời - bạn có được phép thêm câu trả lời cho câu hỏi của riêng bạn không? Hoặc tôi có thể thêm nó chỉ vào ý kiến ​​của bạn? Chúc mừng v nhiều anyways;] – davidfrancis

Trả lời

8

Tôi không thể trả lời câu hỏi của riêng mình vì tôi đã quá nhanh cho StackOverflow - vì vậy chỉ để thực hiện việc này, tôi thêm câu trả lời lần nữa :)

Hóa ra, tôi gần như ở đó.

Cuộc gọi thành lập gọi lại như sau:

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

Sau đó, trong khi gọi lại chức năng, tôi làm điều này:

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

Và nó hoạt động ...

+0

Có một lý do bạn không thể chỉ sử dụng __bridge? Tôi nhận được sự cố khi truy cập đối tượng sau khi sử dụng phương pháp này. –

+0

Làm việc cho tôi. @AlastairStuart Tôi nghĩ rằng điểm là khi bạn vượt qua đối tượng để 'AudioServicesAddSystemSoundCompletion' bạn làm __bridge_retained mà sẽ tăng retainCount bởi 1. __bridge đảm bảo không có chuyển quyền sở hữu, do đó, truy cập sẽ ở lại giống nhau trong gọi lại. CFRelease sau đó sẽ giảm retainCount xuống 1 và cuối cùng xóa đối tượng. – Andy

+0

Liệu CFRelease có nằm trong 'theClass' chứ không phải 'bản thân'? – shim

4

Đối với bất kỳ ai cần thêm một chút trợ giúp ... Tôi nhận được câu trả lời của Swissdude để làm việc trong bộ điều khiển xem chung như vậy:

lưu ý: (bạn không thể sử dụng CFRelease (bản thân mình))

.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...