Cómo detener o cancelar la ejecución del bloque de envío

Quiero ejecutar múltiples bloques de despacho al mismo time. Entonces, cuando cualquier bloque de envío está en progreso al mismo time cuando ejecuto el segundo bloque de envío, quiero detener la ejecución del bloque de envío anterior.

Estoy usando este código a continuación:

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); }); }); 

Y también probé este código a continuación. pero si usé este código a continuación, es posible cancelar el bloque anterior, pero mi aplicación se bloquea

 //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); }]; }]; 

Gracias por adelantado,

No se necesitan queues de envío ni queues de operación aquí.

Solo debe poder iniciar una session de descarga asíncrona con NSURLSession y, cuando la descarga sea exitosa, inicie el AVAudioPlayer asíncrono. Y debido a que son tareas asíncronas, puede cancel o stop , respectivamente.

Aquí hay un ejemplo trivial:

 @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 shanetworkingSession] 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 

Entonces puedes ver que downloadAndPlay inicia la downloadAndPlay asíncrona y, cuando eso sucede, inicia la reproducción asíncrona de la pista. El método de cancel cancela la descarga si está en curso y detiene la reproducción si está en curso.

Y luego puedes usarlo así:

 @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 

Ahora, claramente, esta es una implementación trivial (realmente no quieres hacer NSAssert si tienes algún error, sino que lo manejas con elegancia, quieres manejar una serie de objects Song , es posible que quieras desvincular la descarga de la reproducción para que puede comenzar a download la canción 2 mientras se reproduce la canción 1, etc.), pero ilustra el concepto más amplio de cancelar una descarga o la reproducción de una canción, las cuales ya son tareas asíncronas, por lo que no se necesitan queues de envío ni queues de operación . Puedes hacerlo si quieres ser elegante, pero ese es un tema más avanzado.

Por cierto, NSURLSession es bastante estricto al prohibir requestes que no son de https debido al riesgo de security que representan, pero puede editar su info.plist (haga clic derecho sobre él y luego diga "Abrir como" – "Código fuente") y luego ingrese algo como:

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