6

我正在创建一个可以淡入淡出音乐的程序。问题是其他线程/队列可以暂停音乐,这意味着淡入和淡出不仅需要暂停,还需要暂停。我需要能够在 dispatch_after 上暂停“计时器”(因为在音乐开始播放时调用它以告诉它何时开始淡出,如果它被暂停则需要延迟)并暂停队列本身(为了在淡入或淡出时暂停淡入或淡出)

这是代码(fadeIn 和 delayFadeOut 都在程序开始时调用):

- (void) doFadeIn: (float) incriment to: (int) volume with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue{
    dispatch_async(queue, ^{
        double delayInSeconds = .1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, queue, ^(void){
            thisplayer.volume = (thisplayer.volume + incriment) < volume ? thisplayer.volume + incriment : volume;
            NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
            if (thisplayer.volume < volume) {
                [self doFadeIn:incriment to:volume with:thisplayer on:queue];
            }
        });
    });    
}

-(void) doDelayFadeOut: (float) incriment with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue
{
    dispatch_async(queue, ^{
        double delayInSeconds = .1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, queue, ^(void){
            thisplayer.volume = (thisplayer.volume - incriment) > 0 ? thisplayer.volume - incriment : 0;
            NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
            if (thisplayer.volume > 0.0) {
                [self doDelayFadeOut:incriment with:thisplayer on:queue];
            }
        });
    });
}

-(void) fadeIn: (AVAudioPlayer*) dFade {
    if (dFade == nil) {
        return;
    }
    dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
    dispatch_async( queue, ^(void){
        if(dFade !=nil){
            double incriment = ([self relativeVolume] / [self fadeIn]) / 10; //incriment per .1 seconds.
            [self doFadeIn: incriment to: [self relativeVolume] with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
        }

    });
}

- (void) delayFadeOut: (AVAudioPlayer*) dFade { //d-fade should be independent of other threads
    if (dFade == nil) {
        return;
    }
    int timeRun = self.duration - self.fadeOut;
    dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
    dispatch_time_t mainPopTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeRun * NSEC_PER_SEC));
    printf("test");
    dispatch_after(mainPopTime, queue, ^(void){
        if(dFade !=nil){
            double incriment = ([dFade volume] / [self fadeOut])/10; //incriment per .1 seconds.
            [self doDelayFadeOut:incriment with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
        }

    });
    if (self.cueType == 2) {
        [self callNext];
    }
}
4

2 回答 2

10

对于您的一般性问题,呼叫是dispatch_suspend()(连同dispatch_resume())。这将防止特定队列上的任何新块被调度。它不会对已经运行的块产生任何影响。如果您想暂停已安排并正在运行的块,则由您的代码检查一些条件并暂停。

但是,在使用它时要理解的关键是没有任何东西可以“暂停 dispatch_after 上的“计时器”。” 如果你说要在 1 秒后发送,那么它绝对会在 1 秒后发送。但“调度”并不意味着“运行”。它的意思是“排队”。如果该队列被挂起,则该块将挂起,直到队列恢复。需要注意的是,您不希望一堆淡入淡出块堆积在队列中。如果他们这样做了,当您恢复队列时,他们都将被安排为背靠背。查看您的代码,这可能不会发生,因此这可能对您有用。请记住,调度意味着“排队”。非暂停队列按顺序安排它们的块。

于 2013-03-17T23:52:58.903 回答
6

对于挂起队列/取消操作,您应该使用NSOperationandNSOperationQueue而不是 GCD。见这里

于 2013-03-17T21:02:15.863 回答