ios - example - GCD-hilo principal contra el de fondo para actualizar un UIImageView
grand central dispatch swift (4)
Sí, debe usar el hilo principal cuando toque UIImageView
, o cualquier otra clase UIKit (a menos que se indique lo contrario, como cuando se construye UIImage
s en hilos de fondo).
Un comentario acerca de su código actual: debe asignar weakSelf
en una variable local fuerte antes de usarlo. De lo contrario, su condicional podría pasar, pero luego weakSelf
puede agotarse antes de que realmente intente usarlo. Se vería algo así como
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];
__strong __typeof__(weakSelf) strongSelf = weakSelf;
if ([strongSelf.scrollView viewWithTag:tagNumber] != nil){
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof__(weakSelf) strongSelf = weakSelf;
if ([strongSelf.scrollView viewWithTag:tagNumber]!= nil){
UIImageView * tmpImageView = (UIImageView*)[strongSelf.scrollView viewWithTag:tagNumber];
tmpImageView.image = tmpImage;
}
});
}
});
Técnicamente, no es necesario hacer esto en el primer condicional en la cola de fondo, porque solo se está desviando la referencia una vez allí, pero siempre es una buena idea almacenar su variable débil en una variable fuerte antes de tocarla como una cuestión de curso.
Soy nuevo en GCD y en los bloques y me estoy abriendo camino hacia él.
Antecedentes: Estoy trabajando en una rutina de carga lenta para un UIScrollView utilizando la biblioteca de ALAssets. Cuando se carga mi UIScrollView, lo aspectRatioThumbnails
con el aspectRatioThumbnails
de mis ALAssets y luego, a medida que el usuario se desplaza, llamo a la rutina a continuación para cargar la fullScreenImage
de fullScreenImage
del ALAsset que se muestra actualmente. Parece funcionar.
(Si alguien tiene una rutina de carga perezosa mejor, por favor publique un comentario. He visto todo lo que pude encontrar más el video de la WWDC pero parece que tratan más con el mosaico o tienen mucha más complejidad de la que necesito)
Mi pregunta: utilizo un hilo de fondo para manejar la carga de la imagen de fullScreenImage
y cuando fullScreenImage
, uso el hilo principal para aplicarlo a UIImageView. ¿Necesito usar el hilo principal? He visto que todas las actualizaciones de UIKit deben suceder en el hilo principal, pero no estoy seguro de si eso se aplica a un UIImageView. Estaba pensando que sí, ya que es un elemento de pantalla, pero luego me di cuenta de que simplemente no lo sabía.
- (void)loadFullSizeImageByIndex:(int)index
{
int arrayIndex = index;
int tagNumber = index+1;
ALAsset *asset = [self.assetsArray objectAtIndex:arrayIndex];
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];
if ([weakSelf.scrollView viewWithTag:tagNumber] != nil){
dispatch_async(dispatch_get_main_queue(), ^{
if ([weakSelf.scrollView viewWithTag:tagNumber]!= nil){
UIImageView * tmpImageView = (UIImageView*)[weakSelf.scrollView viewWithTag:tagNumber];
tmpImageView.image = tmpImage;
}
});
}
});
}
Sí, debe utilizar el hilo principal, ya que cualquier cambio en la interfaz de usuario debe realizarse en el hilo principal.
En cuanto al uso del GCD, se utiliza para aprovechar las ventajas de los núcleos múltiples en el dispositivo. En cuanto al yo fuerte y débil.
Yo fuerte : es posible que desee un yo fuerte, porque en su código
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
(<your class> *) *strongSelf = weakSelf;
UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];
if ([strongSelf.scrollView viewWithTag:tagNumber] != nil){
dispatch_async(dispatch_get_main_queue(), ^{
if ([strongSelf.scrollView viewWithTag:tagNumber]!= nil){
UIImageView * tmpImageView = (UIImageView*)[strongSelf.scrollView viewWithTag:tagNumber];
tmpImageView.image = tmpImage;
}
});
}
});
digamos que tiene una vista que hace una llamada a la API y lleva tiempo, por lo que cambia a otra vista, pero aún así desea que la imagen se descargue y luego se utilice con fuerza, ya que el bloque es el propietario y la imagen se descarga.
Yo débil : si en la situación anterior no quieres que la imagen se descargue una vez que te muevas a una vista diferente, entonces usa un Yo débil, ya que el bloque no posee ningún yo.
Si necesita renderizar la imagen en UIImageView
, debe hacerlo en el hilo principal. No funcionará a menos que lo haga en la cola principal como se muestra en su código. Igual es el caso con cualquier representación de interfaz de usuario.
if ([weakSelf.scrollView viewWithTag:tagNumber]!= nil){
UIImageView * tmpImageView = (UIImageView*)[weakSelf.scrollView viewWithTag:tagNumber];
tmpImageView.image = tmpImage;
}
Según la documentación de Apple ,
Consideraciones de subprocesos : Las manipulaciones de la interfaz de usuario de su aplicación deben ocurrir en el subproceso principal. Por lo tanto, siempre debe llamar a los métodos de la clase UIView desde el código que se ejecuta en el hilo principal de su aplicación. La única vez que esto puede no ser estrictamente necesario es cuando se crea el objeto de vista en sí, pero todas las otras manipulaciones deben ocurrir en el hilo principal.
Si no va a utilizar strongSelf en el código sugerido por Kevin Ballard, entonces podría producirse una caída debido a la debilidad de la aniquilación.
También sería una buena práctica incluso verificar si el nivel de ser fuerte es nulo en el momento de crear
strongSelf = weakSelf
if(strongSelf)
{
// do your stuff here
}