ios - framework - UIPageViewController se bloquea cuando se voltea demasiado rápido durante la memoria baja
uipageviewcontroller swift 4 (5)
Aquí hay un cambio adicional que hice, que alguien podría encontrar útil:
Básicamente, solo permito que comience un nuevo giro de página si el anterior ha terminado.
Estoy usando el proyecto predeterminado de Apple PageViewController como plantilla, así que usaré los términos definidos en ese proyecto.
Cada vez que se solicita un VC de página a través de viewControllerAtIndex :, establezco un valor booleano en ModelController llamado '' shouldDenyVC
'' en YES
.
En mi EbookViewController, que es el delegado de UIPageViewController, capturo los reconocedores de gestos y asigno EbookViewController como su delegado:
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
for (UIGestureRecognizer *gr in self.view.gestureRecognizers) {
gr.delegate = self;
}
Entonces, puedo negar un giro de página negando los reconocedores de gestos:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch
{
if (_modelController.shouldDenyPageTurn == YES) {
return FALSE;
}
return TRUE;
}
Y, finalmente, configuré _modelController.shouldDenyPageTurn = NO
al final del método del delegado pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:
También tuve que configurar _modelController.shouldDenyPageTurn = NO
al final de cualquier precarga para que se puedan _modelController.shouldDenyPageTurn = NO
turnos de la página.
Tuve algunos problemas de memoria debido a la plantilla de Xcode para un UIPageViewController que almacena en caché todos los datos de la página, así que la cambié para cargar las páginas dinámicamente, así que ahora cuando mi aplicación recibe una advertencia de memoria baja, libera la memoria para la página que no se muestra, pero si el usuario está hojeando las páginas muy rápido tocando el borde de la pantalla, aún se bloquea. Supongo que esto se debe a que no se puede liberar la memoria lo suficientemente rápido cuando se llama didReceiveMemoryWarning. Si el usuario está volteando lentamente, funciona bien. Limité la velocidad a la que el usuario puede voltear páginas, pero todavía sucede. Quiero poder liberar la memoria cada vez que se gire la página y no tener que esperar una advertencia de memoria baja. Estoy usando ARC. ¿Hay alguna forma de hacer esto? ¿O qué más puedo hacer para prevenir esto? Gracias.
EDITAR:
(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController];
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index];
}
(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController];
if (index == NSNotFound || index == MAX_PAGE_INDEX) {
return nil;
}
return [self viewControllerAtIndex:++index];
}
Como no publicó ningún código, es difícil adivinar dónde reside exactamente su problema.
Para forzar la descarga de una vista, puede anular el método
viewDidDisappear:
de las clases de viewcontroller que aparecen enUIPageViewController
.El código se vería así:
- (void)viewDidDisappear:(BOOL)animated { [self didReceiveMemoryWarning]; }
Si también has anulado ReediveMemoryWarning, no olvides llamar
[super didReceiveMemoryWarning];
de eso.También puede haber cierta confusión sobre cómo
UIPageViewControllerDataSource
métodosUIPageViewControllerDataSource
: es posible que tenga algunos ''cables mixtos''. Compruebe la respuesta aceptada here .
Creo que tu hipótesis es correcta, ya que también experimenté un comportamiento similar: cuando pasas a la página siguiente, también por animar bien las cosas, la nueva página se asigna antes de que se desasigne la anterior y toma algunas veces para viejo para ser desasignado. Entonces, cuando volteas lo suficientemente rápido, los objetos se asignan más rápido de lo que se desasignan y, finalmente, (de hecho, muy pronto), tu aplicación se cancela debido al uso de la memoria. El retraso de la desasignación al pasar las páginas se vuelve bastante obvio si sigue la asignación / desasignación de memoria en los Instruments
.
Tienes tres enfoques para esto, IMO:
implemente un método "light"
viewDidLoad
(en realidad, toda la secuencia de inicialización / visualización inicial): en algunas aplicaciones, tiene sentido, por ejemplo, cargar una imagen de baja resolución en lugar de la imagen de alta resolución que se mostrará; o, retrasando ligeramente la asignación de recursos adicionales que su página necesita (acceso a la base de datos, sonido, etc.);use un grupo de páginas, digamos un conjunto de tres páginas (o 5, depende de su aplicación), que siga "reutilizando" para que el perfil de memoria de su aplicación permanezca estable y evite picos;
revise cuidadosamente la forma en que asigna y libera la memoria; en este sentido, a menudo se lee que el autorelease agrega algo de "inercia" al mecanismo de liberación / desasignación, y esto es bastante fácil de entender: si tiene un objeto lanzado automáticamente, su grupo de lanzamientos lo liberará solo cuando pase por el ciclo bucle principal (esto es cierto para el grupo de lanzamientos principal); por lo tanto, si tiene una larga secuencia de métodos que se llaman al pasar la página, esto hará que el lanzamiento / dealloc suceda más tarde.
No hay una viñeta mágica cuando se trata de la optimización del uso de la memoria, es un trabajo bastante detallado y difícil, pero IME podrá reducir el perfil de memoria de su aplicación si revisa su código y aplica esas 3 pautas. Especialmente, inspeccionar los picos de asignación de memoria en los instrumentos y tratar de entender a qué se relacionan es extremadamente poderoso.
Hay un error en iOS5 en este momento que hace que una vista de desplazamiento pierda una pequeña cantidad de memoria.
¿Ha intentado perfilar su aplicación en instrumentos que verifican las asignaciones y las pérdidas de memoria?
Puede simular una advertencia de memoria baja en el simulador (hardware -> simular advertencia de memoria baja). O puede hacerlo a través de un código, (solo recuerde eliminar después de la depuración porque esto hará que su aplicación sea rechazada)
[[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)];
Si está usando propiedades strong
o retain
, nil
en nil
después de que haya terminado con ellas y ARC liberará la memoria a la que apuntan detrás de la escena.
Si está creando muchos objetos temporales (objetos que no son propiedades o no están asignados), a continuación, inserte un grupo de autorelease:
@autoreleasepool {
}
Y, por último, muestra algo de código y podemos ayudarte mejor.
Puede ser causada por Rendering. Cuando el flipper es demasiado rápido, la memoria y la CPU utilizadas para volver a dibujar la "Página" aumentarán rápidamente. Si las vistas que usó en UIPageViewController se basan en CALayer y tienen demasiadas páginas, al voltear demasiado rápido definitivamente se bloqueará la aplicación.
Una solución es personalizar la capa y almacenar en caché el resultado de la representación. Re-renderiza el contenido solo cuando es necesario. Pero el caché puede aumentar el uso de memoria.