-1

私の目標は、メイン スレッド/GUI の速度を落とさずに、バックグラウンドで一時停止して一連のサウンドを再生することです。

Time Profiler Instrument を使用してコードを実行すると、次のようになります。AudioStateMachine init は GCD を使用して別のスレッドにディスパッチされますが、AudioStateMachine の他のメソッドはメイン スレッドで実行されます。メインで実行しないようにするには、AudioStateMachine のすべてのメソッドが必要です。

Running Time    Self        Symbol Name
87.0ms    8.7%  0.0     Main Thread  0x8531c
84.0ms    8.4%  0.0      start
84.0ms    8.4%  83.0          main
1.0ms    0.1%   0.0        -[AudioStateMachine audioPlayerDidFinishPlaying:successfully:]
1.0ms    0.1%   1.0         -[AudioStateMachine play:]
1.0ms    0.1%   1.0      -[AudioStateMachine states]
1.0ms    0.1%   1.0      -[AudTabController viewDidLoad]
1.0ms    0.1%   1.0      instruments_notifier
4.0ms    0.4%   0.0     _dispatch_worker_thread2  0x85371
4.0ms    0.4%   1.0      __38-[ScreeningViewController viewDidLoad]_block_invoke
3.0ms    0.3%   0.0       -[AudioStateMachine init]

オーディオ バックグラウンド タスクをディスパッチするビュー コントローラーのコード:

controller.h
@interface ScreeningViewController : UIViewController {
    UIButton *okButton;
    UIProgressView *bar;
    AudioStateMachine *test;
}
@property(nonatomic, strong) UIButton *okButton;
@property(nonatomic, strong) UIProgressView *bar;

-(IBAction)okPressed:(id)sender;
@end

コントローラー.m

@implementation ScreeningViewController
@synthesize okButton;
@synthesize bar;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

-(void)okPressed:(id) sender{
    NSLog(@"OK button pressed");
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    //kick off state machine
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        test = [[AudioStateMachine alloc] init];
    });
}
@end

そして AudioStateMachine.h:

@interface AudioStateMachine : NSObject <AVAudioPlayerDelegate>
{
    AVAudioPlayer *player;
    NSArray *soundList;
    int index;
}

@property(nonatomic, strong) AVAudioPlayer *player;
@property(nonatomic, strong) NSArray *soundList;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (id)init;
- (void)play:(int)i;
@end

そして.m:

@implementation AudioStateMachine
@synthesize player, soundList;

-(id)init
{
    if ((self = [super init]))
    {
        soundList = [[NSArray alloc] initWithObjects:@"1",@"2",@"3",@"4",nil];
        index = 0;
        [self play:index];
    }
    else
        NSLog(@"Error initializing AudioStateMachine");
    return self;
}

-(void) play:(int)i
{
    NSError *error;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSURL alloc]  initFileURLWithPath:[[NSBundle mainBundle] pathForResource:[soundList objectAtIndex:i] ofType:@"wav"]] error:&error];
    player.delegate = self;
    [player prepareToPlay];
    [player play];
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    [NSThread sleepForTimeInterval:1.5];
    if (index < soundList.count) {
        index++;
        [NSThread sleepForTimeInterval:1.0];
        [self play:index];
    } else {
        NSLog(@"Reached end of sound list.");//reached end of queue
    }
}
@end

助けていただければ幸いです。

4

1 に答える 1

2

スレッドはオブジェクトが存在する場所ではなく、実行される一連の命令です。スレッド上でオブジェクトを作成するということは、その特定のスレッドを実行する一部として、CPU がコードを実行してオブジェクトを設定したことを意味するだけです。そのオブジェクトのインスタンス メソッドがどのスレッドで実行されるかについて、将来的に影響を与えることはありません。

オブジェクトのすべての作業をバックグラウンド スレッドで実行する必要がある場合は、すべてのメソッドを実装して、それらの作業を並行キューにディスパッチできます。不自然な例として:

- (void)aMethod
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        // do all your method's work here…
    });
}

また、次のトラックの再生を遅らせるためだけにスレッドをスリープ状態にするのは、間違ったアプローチだと思います。最新の同時実行アプローチに適した、混乱の少ない方法がいくつかあります。たとえば、dispatch_after().

于 2013-03-18T09:25:38.860 に答える