ios如何停止或取消调度块的执行

发布时间: 2017/4/3 18:38:08
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我想要在同一时间执行多个调度块。所以当任何调度块同时当我运行调度的第二块是在进步,我想停止以前的调度块的执行。

我用这个代码如下︰

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:item.URL];
        dispatch_async(dispatch_get_main_queue(), ^(void){
         NSError *error = nil;
         self.player =[[AVAudioPlayer alloc] initWithData:data fileTypeHint:AVFileTypeMPEGLayer3 error:&error];
            NSLog(@"%@",error);
        });
    });

我也尝试过这下面的代码。但如果我用这个添加的代码下面是可能取消前一个块但我的应用程序去挂

//Use NSOperationQueue 
    myQueue = [NSOperationQueue mainQueue];
    [myQueue addOperationWithBlock:^{

        // Background work
        NSData *data = [NSData dataWithContentsOfURL:item.URL];
       [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            // Main thread work (UI usually)
            NSError *error = nil;
           self.player =[[AVAudioPlayer alloc] initWithData:data fileTypeHint:AVFileTypeMPEGLayer3 error:&error];
            NSLog(@"%@",error);
        }];
    }];

提前谢谢,

解决方法 1:

在这里需要没有调度队列操作。

你只需要能够启动异步下载会话与 NSURLSession 和成功下载后,启动异步 AVAudioPlayer 。因为那些异步任务,您可以选择和 cancelstop 他们分别。

这里是一个小例子︰

@class Song;

@protocol SongDelegate <NSObject>

- (void)song:(Song *)song didFinishPlayingSuccessfully:(BOOL)flag;
- (void)song:(Song *)song didFinishDownloadWithError:(NSError *)error;

@end

@interface Song: NSObject <AVAudioPlayerDelegate>
@property (nonatomic, strong) NSURL *url;
@property (nonatomic, weak)   NSURLSessionTask *downloadTask;
@property (nonatomic, strong) NSURL *localURL;
@property (nonatomic, strong) AVAudioPlayer *player;
@property (nonatomic, weak)   id<SongDelegate> delegate;
@end

@implementation Song

+ (instancetype)songWithURL:(NSURL *)url delegate:(id<SongDelegate>)delegate {
    Song *song = [[Song alloc] init];
    song.url = url;
    song.delegate = delegate;
    return song;
}

- (void)downloadAndPlay {
    self.downloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:self.url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.delegate song:self didFinishDownloadWithError:error];
        });
        NSURL *documentsURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
        NSAssert(documentsURL, @"URLForDirectory failed: %@", error);
        NSURL *fileURL = [documentsURL URLByAppendingPathComponent:self.url.lastPathComponent];
        NSError *moveError;
        BOOL success = [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&moveError];
        NSAssert(success, moveError.localizedDescription);

        // note, the only reason we dispatch the following is that this completion handler runs on background queue and we want to update properties and start the player from the main queue

        dispatch_async(dispatch_get_main_queue(), ^{
            self.localURL = fileURL;
            NSError *playError;
            self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&playError];
            self.player.delegate = self;
            [self.player play];
            NSAssert(playError == nil, playError.localizedDescription);
        });
    }];
    [self.downloadTask resume];
}

- (void)cancel {
    [self.downloadTask cancel];  // if download still in progress, stop it
    [self.player stop];          // if playing, stop it
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    self.player = nil;
    [self.delegate song:self didFinishPlayingSuccessfully:flag];
}

@end

所以你可以看到, downloadAndPlay 启动异步下载,当这样做,开始异步播放的轨道。cancel方法取消下载如果进展和停止播放如果在进步。

然后你可以使用它就像这样︰

@interface ViewController () <SongDelegate>

@property (nonatomic, strong) Song *song;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.song = [Song songWithURL:[NSURL URLWithString:@"http://dl.last.fm/static/1464677535/131211148/70b3b5a9d048c7939d5bb9ec87a2c5d58d6ee528828f5c6a5b7b1eddd69f4553/Death+Grips+-+Get+Got.mp3"] delegate:self];

    // Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)didTapPlayButton:(id)sender {
    [self.song downloadAndPlay];
}

- (IBAction)didTapStopButton:(id)sender {
    [self.song cancel];
}

- (void)song:(Song *)song didFinishPlayingSuccessfully:(BOOL)flag {
    NSLog(@"did finish playing %@", flag ? @"successfully" : @"unsuccessfully");
}

- (void)song:(Song *)song didFinishDownloadWithError:(NSError *)error {
    NSLog(@"did finish download with error %@", error.localizedDescription);
}
@end

现在,显然,这微不足道的执行 (你真的不想要 NSAssert 如果您有任何的错误,但宁可优雅地处理它,你想要处理一系列的 Song 对象,您可能想要解耦从玩下载,以便您可以开始下载首歌 2,而占据着歌曲 1 等),但它说明了更广泛的概念取消下载或播放一首歌这两个国家已经是异步任务,因此需要没有调度队列或操作队列。如果你想要弄点花样,但这是一个更高级的主题,你可以做到。

顺便说一句, NSURLSession 是他们构成关于禁止非 https 请求由于安全风险相当严格,但您可以编辑您 info.plist (右击它,然后说"打开为"-"源代码"),然后输入类似︰

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>dl.last.fm</key>
        <dict>
            <!--Include to allow subdomains-->
            <key>NSIncludesSubdomains</key>
            <true/>
            <!--Include to allow HTTP requests-->
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <!--Include to specify minimum TLS version-->
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
        </dict>
    </dict>
</dict>
官方微信
官方QQ群
31647020