Cómo cerrar AVPlayer anterior y AVPlayerItem

Estoy haciendo una aplicación de iOS en Swift que reproduce un video en un bucle en una pequeña capa en la esquina superior derecha de la pantalla que muestra un video de un artículo de color específico. el usuario luego toca el elemento coloreado correspondiente en la pantalla. cuando lo hacen, la variable videoName se cambia aleatoriamente al siguiente color y se dispara el video correspondiente. No tengo problemas para upload, reproducir y reproducir el video con AVPlayer, AVPlayerItem como se ve en el código adjunto. Donde estoy atrapado es que cada vez que se muestra el siguiente video, los anteriores permanecen abiertos detrás de él. Además, después de que se hayan reproducido 16 videos, el reproductor desaparecerá por completo en mi iPad. He probado muchas sugerencias presentadas en este y otros sitios, pero Swift encuentra un problema con ellos o simplemente no funciona. Entonces, pregunta: dentro de mi código aquí, ¿cómo puedo decirle "oye que el próximo video ha comenzado a reproducirse, eliminar el video anterior y es capa y liberar memory para poder reproducir tantos videos como sea necesario"?

//set variables for video play var playerItem:AVPlayerItem? var player:AVPlayer? //variables that contain video file path, name and extension var videoPath = NSBundle.mainBundle().resourcePath! var videoName = "blue" let videoExtension = ".mp4" //DISPLAY VIDEO func showVideo(){ //Assign url path let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension) playerItem = AVPlayerItem(URL: url) player=AVPlayer(playerItem: playerItem!) let playerLayer=AVPlayerLayer(player: player!) //setplayser location in uiview and show video playerLayer.frame=CGRectMake(700, 5, 350, 350) self.view.layer.addSublayer(playerLayer) player!.play() // Add notification to know when the video ends, then replay it again. THIS IS A CONTINUAL LOOP NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil) { notification in let t1 = CMTimeMake(5, 100); self.player!.seekToTime(t1) self.player!.play() } } 

¿Por qué no utilizas replaceCurrentItemWithPlayerItem en tu reproductor? Mantendrás el mismo jugador para todos tus videos. Creo que es una mejor manera de hacerlo.

Edit: replaceCurrentItemWithPlayerItem tiene que ser llamada en el hilo principal

Antes de pasar a la siguiente pista, primero verifique si el jugador tiene videos o música, para evitar que realice las siguientes comprobaciones:

Código SWIFT-

 if (player!.rate>0 && player!.error == nil) { player!.pause(); player = nil } 

Objetivo-C Código-

 if (player.rate>0 && !player.error) { [player setRate:0.0]; } 

Adapté la sugerencia del código Swift de @Anupam Mishra. No funcionó al principio, pero finalmente pensé que tenía que sacar al jugador fuera de la function y cerrar el jugador después de que dejé el jugador en cero. También. en lugar de usar 'if (player! .rate> 0 …)', que sin duda seguiría funcionando, creé un interruptor de variable para indicar cuándo decir "matar al jugador Y la capa" como se ve a continuación. Puede que no sea bonito, pero funciona. Lo siguiente es para novatos absolutos como yo : LO QUE APRENDÍ DE ESTA EXPERIENCIA: me parece que un dispositivo iOS solo permite agregar 16 capas a un viewController (o superLayer). por lo que cada capa debe eliminarse antes de abrir la siguiente capa con su reproductor, a less que realmente desee que 16 capas se ejecuten de una sola vez. LO QUE ESTE CÓDIGO ABAJO REALMENTE HACE PARA USTED: este código crea una capa re-dimensionable sobre un viewController existente y reproduce un video de su package en un bucle sin fin. Cuando se va a llamar al próximo video, el video actual y la capa se eliminan por completo, liberando la memory, y luego se reproduce una nueva capa con el nuevo video. El tamaño y la location de la capa de video es totalmente personalizable mediante los parameters playerLayer.frame = CGRectMake (izquierda, arriba, ancho, alto). CÓMO HACERLO TODO EL TRABAJO: Suponiendo que ya ha agregado sus videos a su package, cree otra function para que toque su button. en esa function, primero llame a la function 'stopPlayer ()', cambie la variable 'videoName' por el nuevo nombre de video que desee y luego llame a la function 'showVideo ()'. (si necesita cambiar la extensión de video, cambie 'videoExtension' de let a a var.

 //set variables for video play var playerItem:AVPlayerItem? var player:AVPlayer? var playerLayer = AVPlayerLayer() //NEW playerLayer var location //variables that contain video file path, name and extension var videoPath = NSBundle.mainBundle().resourcePath! var videoName = "blue" let videoExtension = ".mp4" var createLayerSwitch = true /*NEW switch to say whether on not to create the layer when referenced by the closePlayer and showVideo functions*/ //DISPLAY VIDEO func showVideo(){ //Assign url path let url = NSURL(fileURLWithPath: videoPath+"/Base.lproj/"+videoName+videoExtension) playerItem = AVPlayerItem(URL: url) player=AVPlayer(playerItem: playerItem!) playerLayer=AVPlayerLayer(player: player!) //NEW: remove 'let' from playeLayer here. //setplayser location in uiview and show video playerLayer.frame=CGRectMake(700, 5, 350, 350) self.view.layer.addSublayer(playerLayer) player!.play() createLayerSwitch = false //NEW switch to tell if a layer is already created or not. I set the switch to false so that when the next tapped item/button references the closePlayer() function, the condition is triggenetworking to close the player AND the layer // Add notification to know when the video ends, then replay it again without a pause between replays. THIS IS A CONTINUAL LOOP NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil) { notification in let t1 = CMTimeMake(5, 100); self.player!.seekToTime(t1) self.player!.play() } } //NEW function to kill the current player and layer before playing the next video func closePlayer(){ if (createLayerSwitch == false) { player!.pause() player = nil playerLayer.removefromsuperlayer() } }