ios objective-c multithreading uicollectionview uicollectionviewcell

ios - Cargue un video en un UICollectionViewCell con una cadena de fondo para crear un desplazamiento continuo



objective-c multithreading (4)

Estoy trabajando con una aplicación Objective-C que presenta una escena con una pantalla completa que se desplaza horizontalmente UICollectionView. Actualmente tengo una función que se llama cada vez que aparece una nueva celda en la pantalla durante el desplazamiento que tarda unos 3-4 segundos para ejecutar y edita los elementos de la interfaz de usuario dentro de la celda que acaba de aparecer. Debido a esto, mi aplicación se demora cada vez que una nueva celda ingresa a la pantalla durante aproximadamente 4 segundos y luego continúa desplazándose normalmente.

¿Hay alguna manera de editar esta función y ponerla en un hilo de fondo para que en lugar de un retraso de 4 segundos en el desplazamiento, haya un desplazamiento ininterrumpido sin interrupciones? Entiendo que esta solución provocará una demora de 4 segundos para que aparezcan los elementos de la interfaz de usuario, pero estoy de acuerdo con eso, siempre que haya un desplazamiento continuo.

EDITAR: No pensé que sería una buena idea publicar el código para este problema ya que el código en la función que realiza la carga requiere una API de reproductor de video que compré, pero seguiré adelante y publicaré el método a continuación para mostrar qué partes de la función editan la IU.

//variables declared in other parts of the file KolorEyes *myKolorEyesPlayer; UICollectionView *collectionViewFollwersFeed; NSIndexPath *lastPath = nil; //called repeatedly while scrolling -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ if(scrollView==_collectionViewFollwersFeed) { [self tsLoad]; //function call } } - (void)tsLoad { //calculate index path of cell in the center of the screen NSIndexPath *centerCellIndexPath = [self.collectionViewFollwersFeed indexPathForItemAtPoint: [self.view convertPoint:[self.view center] toView:self.collectionViewFollwersFeed]]; if(centerCellIndexPath != lastPath) //condition is satisfied if a new cell has been scrolled to the center { lastPath = centerCellIndexPath; UICollectionViewCell *cell; NSString *CellIdentifier; //initialize cell from center path CellIdentifier = @"FollowersFeed"; cell = [_collectionViewFollwersFeed cellForItemAtIndexPath:centerCellIndexPath]; //get respective url for video player NSMutableDictionary *dict1=[follwerFeed objectAtIndex:centerCellIndexPath.row]; NSString *tsstring= [dict1 valueForKey:@"video"]; NSURL *tsurl = [[NSURL alloc] initWithString:tsstring]; //view that the video will be played in UIView *tsView = (UIView *)[cell viewWithTag:99]; //API-specific parameters for video player session KolorEyesSessionParams *params = [[KolorEyesSessionParams alloc] init]; params.delegate = self; /* other params properties set like above at this point... ... ... */ //API-specific initialization myKolorEyesPlayer = [[KolorEyes alloc] initWithParams:params]; //API-specific parameters for video player view KolorEyesRenderViewParams *fparams = [[KolorEyesRenderViewParams alloc] init]; fparams.cameraFieldOfView = 90; /* other fparams properties set like above at this point... ... ... */ //API-specific initializations id _tsViewHandle = [myKolorEyesPlayer setRenderView: tsView withParams:fparams]; [myKolorEyesPlayer setCameraControlMode:kKE_CAMERA_MOTION forView:_tsViewHandle]; __block KolorEyes *player = myKolorEyesPlayer; //error checking eKEError err = [myKolorEyesPlayer setAssetURL: tsurl withCompletionHandler:^{ // Media is loaded, play now [player play]; }]; if (err != kKE_ERR_NONE) { NSLog(@"Kolor Eyes setAssetURL failed with error"); } } }


¿Hay alguna manera de editar esta función y ponerla en un hilo de fondo para que en lugar de un retraso de 4 segundos en el desplazamiento, haya un desplazamiento ininterrumpido sin interrupciones?

Está ejecutando un SDK como usted menciona:

Kolor Eyes es una aplicación gratuita de reproducción de videos 360 que representa videos esféricos con algoritmos de proyección precisos en píxeles. El usuario puede elegir diferentes puntos de vista de la cámara en cualquier momento a través de gestos táctiles o controles de movimiento del dispositivo. Más que un jugador, es el navegador perfecto diseñado para el sitio web de alojamiento de videos Kolor 360. Esta documentación se refiere a Kolor Eyes iOS desde la versión 2.0

Es suficiente con ejecutar el propio "AVPlayer" de Apple en un UICollectionView / UITableView sin demoras, y desea ejecutar un reproductor de video 360 por encargo sin rezagos.

Como se trata de un SDK, no puede acceder y / o modificar ninguno de los códigos , debe ponerse en contacto con los desarrolladores del SDK para obtener las pautas. No creo que este SDK esté desarrollado para ser ejecutado en un scrollView en mente, ya que esto parece ser una tarea pesada (no estoy seguro al 100%, sin embargo, debes preguntarle a los desarrolladores).

Sin embargo , no debe modificar la interfaz de usuario en un hilo de fondo mientras pregunta, eso no ayudará a que los rezagos desaparezcan, empeorará e incluso colgará o bloqueará su aplicación en la mayoría de los casos, y estoy seguro (espero que al menos) que los desarrolladores ya hacen la mayor cantidad de subprocesos posible con este SDK:

En una aplicación Cocoa, el hilo principal ejecuta la interfaz de usuario, es decir, todos los dibujos y todos los eventos se manejan en el hilo principal. Si su aplicación realiza operaciones largas sincrónicas en ese hilo, su interfaz de usuario puede dejar de responder y desencadenar el cursor giratorio. Para evitar esto, debe acortar la cantidad de tiempo consumido por esas operaciones, diferir su ejecución o moverlas a subprocesos secundarios.

Fuente


En teoría, tienes razón. Debería poder realizar una carga de video no relacionada con la interfaz de usuario (como la descarga del video) en una secuencia de fondo y el envío al tema principal cuando realmente desea mostrarla. En la práctica, he encontrado que esto es muy difícil con muchas bibliotecas de terceros. La mayoría de las videotecas esperan ejecutarse completamente en el hilo principal. Debería verificar con su video sdk, pero me sorprendería si admitieran la carga de fondo.

Otra solución es no cargar el video en el cellForItemAtIndexPath: sino que carga los videos para la celda visible cuando se detiene el desplazamiento. Puede supervisar las devoluciones de scrollViewDidEndDragging del delegado scrollViewDidEndDragging y / o scrollViewDidEndDecelerating .


Oh, he intentado reproducir videos durante el desplazamiento antes. No lo logré en ese entonces ... ¿Cuándo estuviste buscando en Google esto, probablemente también has visto mi pregunta al respecto, ya que tiene mucha lógica? Terminé empezando a reproducir el video cuando el desplazamiento se detuvo, pero eso fue hace mucho tiempo, y ya no estoy trabajando en eso.

Ahora, puedo tener una idea para ti.

Antes de sumergirte en esto, solo voy a decir: Esto funciona, pero no estoy 100% seguro de si funcionará para la reproducción de video. Tendrás que descubrirlo tú mismo. Lo siento por la duración de esto, pero puede ser bastante complejo.

Completamente dependiendo de su situación con el número de celdas, etc., podría estar interesado en deshabilitar la reutilización de celdas y simplemente precompilar todo.

No he hecho esto en UICollectionViewCell antes, y no tengo idea de qué es KolorEyes , pero esto probablemente funcionaría para UITableViewCell y AVPlayer , aunque no tengo el tiempo o la voluntad para probarlo. Trataré de explicar la lógica de lo que estoy pensando.

No he hecho ningún Objective-C en un tiempo, así que lo haré en Swift , pero espero que entiendas lo que estoy pensando: Primero, haz esta clase:

class PrecompiledCell{ var cell:UICollectionViewCell? = nil var size:CGSize? = nil // constructor and such }

Esta clase es solo un contenedor para tu celular. Ahora deberías crear una instancia de PrecompiledCell para cada celda que mostrarás, es decir, una para cada seguidor PrecompiledCell . Debería crear una función llamada precompileCells() y llamarla cada vez que actualice su dataSource ( followerFeed ). Esta función debe recorrer todos los elementos en su follwerFeed array, y crear una celda para cada uno. Al igual que su cellForRowAtIndexPath probablemente esté funcionando hoy.

var followerFeed:[[String:Any]] = [] // Your data. Probably an NSArray with NSDictionaries inside? var precompiledCells:[PrecompiledCell] = [] //Your array of precompiled cells func precompileCells(){ var precompiledCells:[PrecompiledCell] = [] for feed in followerFeed{ //Create the cell let videoCell = UINib(nibName: "MyVideoCell", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! MyVideoCell //Each instance of this cell (MyVideoCell) should already be initialising its very own KolorEyes-player etc., so now you can say this: videoCell.kolorEyesPlayer.setAssetURL(feed["video"]) //Of course, convert String to NSURL etc. first.. let precompiledCell = PrecompiledCell() precompiledCell.cell = videoCell precompiledCell.size = //Find out what size the cell is. E.g by using videoCell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize), or even easier if you have a constant size. precompiledCells.append(precompiledCell) } self.precompiledCells = precompiledCells }

Ahora, es importante no hacer este trabajo dos veces. La idea completa de esta respuesta es que su cellForRowAtIndexPath (o scrollViewDidScroll en su caso) no tiene que hacer todo este trabajo cuando se utiliza el desplazamiento. El motivo de la demora actual es que la vista está inicializando tantas cosas mientras se desplaza. Con estas celdas precompiladas, todo ya se ha inicializado antes de que pueda comenzar a desplazarse. Así que ahora, elimine las inicializaciones y todas las secuencias de sus métodos delegados normales, y haga esto:

func collectionView(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { return self.precompiledCells[indexPath.row].cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return self.precompiledCells[indexPath.row].size }

No más cosas de inicialización mientras se desplaza, porque todo ya se ha inicializado antes. Lo único que tienes que hacer ahora es usar tu función anterior, scrollViewDidScroll , hacer lo mismo que tú (almacenar el índice actual, etc.), y simplemente poner [player play]; , no las otras cosas

Pensamientos importantes

En primer lugar, es realmente importante llamar a collectionView.reloadData() después de self.precompileCells . Entonces debería suceder así:

self.followerFeed = [/*new data*/] self.precompileCells() self.collectionView.reloadData()

Además, esta implementación deshabilitará por completo la eliminación de minas, que en realidad es una mala práctica, hasta donde yo sé. No use esto si está cargando cantidades inmensas de celdas. Entonces más bien trata de dividirlo un poco.

Esta implementación puede causar un retraso en la precompilación en realidad, pero más que retrasar al desplazarse.

Si está cargando celdas en un estilo de paginación (por ejemplo, desplazarse hasta el final cargará más celdas), entonces realmente debería mejorar mi código, ya que volverá a precompilar todas las celdas. Deberías hacer algún tipo de insertPrecompiledCells -thingy.

Tan pronto como haya precompilado sus celdas, cada celda puede decidir por sí misma si debería comenzar a descargar los videos. Si deberían descargar el video completo, solo unos segundos después del comienzo del video, o no lo descarguen antes de solicitarlo. Iniciar una descarga parcial puede ser asincrónico y tendrá un inicio más uniforme al desplazarse sobre él.

Un pensamiento secundario que obtuve al escribir esto es que puede ser una mala idea tener KolorEyes -player para cada célula. Es posible que desee tener un único KolorEyes KolorEyes en todo el mundo, y simplemente pasarlo a la celda correcta, pero aún puede precompilar la celda antes de configurar el reproductor de video, y también puede comenzar a descargar de forma asincrónica el video en sí (sin tener el reproductor ) (dependiendo de qué demonios sea un jugador de KolorEyes, pero te darás cuenta de esa parte ...)

Nuevamente, esta es solo una idea que podría funcionar. Lo he usado para tableViews con celdas complejas para aumentar drásticamente la suavidad del desplazamiento, pero de una manera muy controlada (nunca más de 30 filas, etc.)

Todavía tengo un montón de ideas y pensamientos sobre esto, pero esta publicación ya es demasiado larga, y tengo que irme ahora. ¡Buena suerte!


Puede definir un " NSOperationQueue " para ejecutar operaciones en segundo plano y cuando la celda está visible, puede cargar el video en la celda de UICollectionView.

Además, no olvides aprovechar el NSOperationQueue y llamar a " cancelAllOperations " cuando el collectionView ya no sea necesario.