1

ゲームで BGM を再生したい (理想的にはフェードイン/アウトしたいが、最初に再生したい)

私はSOに関するさまざまな回答を見てきましたが、私のコードは正しいように見えますが、何らかの理由でファイルが再生されていません。実際、AVAudioPlayer *player行でクラッシュします(有用な出力はありません)。[player play]続行すると、回線上で再びクラッシュしますerrorが、 0.

更新しました...もう一度

GameViewController.h

@property (nonatomic, retain) AVAudioPlayer *player;

GameViewController.m

@synthesize player; // the player object

ViewDidLoad:

NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"bgtrack" ofType: @"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error: nil]; // breaks here
[player prepareToPlay];

含めています

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

アップデート:

コメントに従って、Apple Dev center からコードを直接コピー/貼り付けてみました。最新の XCode 4 と iOS 6.1 シミュレーターを使用しています。

クラッシュすると、ブレークポイントにヒットしたという情報バーが表示されません。ファイルはバンドルに含まれています

4

2 に答える 2

3

player(おそらくView Controllerのivarなどに)強い参照を保存する必要があります。-viewDidLoad強い参照をせずにそのコードをメソッドまたは何かに入れると、プレーヤーが再生を開始する前に割り当てが解除されます。例えば:

@interface MyViewController : UIViewController

@end

@implementation MyViewController
{
    AVAudioPlayer* player;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"YourMP3FileName" ofType:@"mp3"];
    NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
    NSError *error;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:&error];
    player.numberOfLoops = -1; //infinite
    player.currentTime = 139;// 2:19;

    [player play];
}

@end

それは私にとってplayerはうまくいきますが、View Controllerのivarでない場合、音が出ません。

別の方法として、「ワンショット」AVAudioPlayer として機能する次のクラスを作成しました。これは明らかに -1 (無限) の場合に問題を引き起こします。これは、numberOfLoops再生が停止したり消えたりすることがないことを意味するためです。それを参照してください。

OneShotAVAudioPlayer.h

#import <AVFoundation/AVFoundation.h>

@interface OneShotAVAudioPlayer : AVAudioPlayer
@end

OneShotAVAudioPlayer.m

#import "OneShotAVAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import <objc/runtime.h>

@interface OneShotAVAudioPlayer () <AVAudioPlayerDelegate>
@property(weak) id<AVAudioPlayerDelegate> p_exogenousDelegate;
@end

@implementation OneShotAVAudioPlayer

static void * const OneShotAVAudioPlayerKey = (void*)&OneShotAVAudioPlayerKey;

- (id)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError
{
    if (self = [super initWithContentsOfURL:url error:outError])
    {
        // Retain ourself
        objc_setAssociatedObject(self, OneShotAVAudioPlayerKey, self, OBJC_ASSOCIATION_RETAIN);
        [super setDelegate: self];
    }
    return self;
}

- (id)initWithData:(NSData *)data error:(NSError **)outError;
{
    if (self = [super initWithData:data error:outError])
    {
                    // Retain ourself
        objc_setAssociatedObject(self, OneShotAVAudioPlayerKey, self, OBJC_ASSOCIATION_RETAIN);
        [super setDelegate: self];
    }
    return self;
}

- (void)setDelegate:(id<AVAudioPlayerDelegate>)delegate
{
    self.p_exogenousDelegate = delegate;
}

- (id<AVAudioPlayerDelegate>)delegate
{
    return self.p_exogenousDelegate;
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    @try
    {
        if ([self.p_exogenousDelegate respondsToSelector: _cmd])
            [self.p_exogenousDelegate audioPlayerDidFinishPlaying:player successfully:flag];
    }
    @finally
    {
        // Make a strong ref so we stay alive through the scope of this function
        typeof(self) keepAlive = self;
        // Give up the self retain
        objc_setAssociatedObject(keepAlive, OneShotAVAudioPlayerKey, nil, OBJC_ASSOCIATION_RETAIN);
        // Push in the "real" (outside) delegate, cause our job is done here.
        [super setDelegate: self.p_exogenousDelegate];
    }
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
    @try
    {
        if ([self.p_exogenousDelegate respondsToSelector: _cmd])
            [self.p_exogenousDelegate audioPlayerDecodeErrorDidOccur:player error:error];
    }
    @finally
    {
        // Make a strong ref so we stay alive through the scope of this function
        typeof(self) keepAlive = self;
        // Give up the self retain
        objc_setAssociatedObject(keepAlive, OneShotAVAudioPlayerKey, nil, OBJC_ASSOCIATION_RETAIN);
        // Push in the "real" (outside) delegate, cause our job is done here.
        [super setDelegate: self.p_exogenousDelegate];
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    BOOL retVal = [super respondsToSelector: aSelector];
    if (!retVal)
    {
        struct objc_method_description method = protocol_getMethodDescription(@protocol(AVAudioPlayerDelegate), aSelector, YES, YES);
        if (method.name)
        {
            retVal = [self.p_exogenousDelegate respondsToSelector: aSelector];
        }
    }
    return retVal;
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    id retVal = [super forwardingTargetForSelector:aSelector];
    if (!retVal)
    {
        struct objc_method_description method = protocol_getMethodDescription(@protocol(AVAudioPlayerDelegate), aSelector, YES, YES);
        if (method.name && [self.p_exogenousDelegate respondsToSelector: aSelector])
        {
            retVal = self.p_exogenousDelegate;
        }
    }
    return retVal;
}

- (void)setNumberOfLoops:(NSInteger)numberOfLoops
{
    if (numberOfLoops < 0)
    {
        NSLog(@"Warning! You have set an infinite loop count for an instance of %@ (%p). This means the instance will effectively be leaked.", NSStringFromClass([self class]), self);
    }
    [super setNumberOfLoops: numberOfLoops];
}

@end

要点としてここに投稿されました。

于 2013-08-24T13:12:40.053 に答える