Mal acceso en [UICollectionView setCollectionViewLayout: animado:]
Estoy teniendo un extraño accidente en mi UICollectionView. El bloqueo de UICollectionView está incrustado en una celda de UICollectionView de otra UICollectionView.
No puedo reproducir el problema, parece suceder a veces si el UICollectionView interno se inicializa nuevamente porque el collectionView externo está recargando sus celdas.
com.apple.main-thread Crashed 0 libobjc.A.dylib objc_msgSend + 9 1 UIKit -[UICollectionViewData _setLayoutAttributes:atGlobalItemIndex:] + 60 2 UIKit __45-[UICollectionViewData validateLayoutInRect:]_block_invoke_0 + 668 3 UIKit -[UICollectionViewData validateLayoutInRect:] + 1408 4 UIKit -[UICollectionViewData layoutAttributesForElementsInRect:] + 82 5 UIKit -[UICollectionView setCollectionViewLayout:animated:] + 1644 6 MyApp BSCTopnewsCollectionView.m line 52 -[BSCTopnewsCollectionView setupBSCTopnewsCollectionView] 7 MyApp BSCTopnewsCollectionView.m line 27 -[BSCTopnewsCollectionView setWeakDelegatePointer:] 8 Myapp BSCFrontPageViewController.m line 550 -[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:] 9 UIKit -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:] + 252 10 UIKit -[UICollectionView _updateVisibleCellsNow:] + 2672 11 UIKit -[UICollectionView layoutSubviews] + 214 12 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 258 13 QuartzCore -[CALayer layoutSublayers] + 214 14 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*) + 460 15 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16 16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 238 17 QuartzCore CA::Transaction::commit() + 316 18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 60 19 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20 25 UIKit UIApplicationMain + 1120 26 MyApp main.m line 16 main Exception Type: EXC_BAD_ACCESS Code: KERN_INVALID_ADDRESS at 0x158848
Lo que estoy haciendo en la línea 52 en setupBSCTopnewsCollectionView es
BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init]; (line 52) self.collectionView.collectionViewLayout = infiniteLayout;
Editar: - [BSCFrontPageViewController collectionView: cellForItemAtIndexPath:]
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if([collectionView isEqual:self.collectionView])
{
if(indexPath.row == 0) // Header Cell
{
BSCTopnewsCollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCHeaderReuseIdentifier forIndexPath:indexPath];
cell.dataSource = self;
cell.weakDelegatePointer = self;
self.topNewsCollectionView = cell;
return cell;
}
else
{
//create normal cells
}
}
else if ([collectionView isEqual:self.topNewsCollectionView.collectionView])
{
BSCTopNewsHeaderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier forIndexPath:indexPath];
BSCNews *topnews = [self.topNews objectAtIndex:indexPath.row];
[cell setEntity:topnews];
return cell;
}
}
Algunas aclaraciones para el método llama allí:
- (void)setWeakDelegatePointer:(BSCFrontPageViewController *)weakDelegatePointer
{
_weakDelegatePointer = weakDelegatePointer;
[self setupBSCTopnewsCollectionView];
[self.collectionView reloadData];
}
- (void)setupBSCTopnewsCollectionView
{
self.collectionView.delegate = self.weakDelegatePointer;
self.collectionView.dataSource = self.weakDelegatePointer;
BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init];
infiniteLayout.delegate = self;
// Setup Layout
self.collectionView.collectionViewLayout = infiniteLayout;
self.collectionView.showsHorizontalScrollIndicator = NO;
self.collectionView.pagingEnabled = YES;
// Register Cells
[self.collectionView registerNib:[UINib nibWithNibName:@"BSCTopNewsHeaderCell" bundle:nil] forCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier];
}
Edit3: El choque solo parece ocurrir en ocasiones especiales. Si la aplicación estaba en segundo plano, pero todavía en la memoria y el usuario la abre de nuevo. Luego revisa nuestra API para nuevos datos, y si encuentra algo los cargará y recargará toda la collectionView externa. Es cuando el choque ocurrir.
Si la collectionView se vuelve a cargar mientras la aplicación se está ejecutando sin estar en segundo plano al principio, todo está bien.
Para que la configuración sea un poco más clara.
![](/images/content/18189311/4fde44fc32a5b83ed753090cfc44542a.png)
4 answers
Primero, arrastre y suelte un UICollectionView a su ViewController en XIB, hook up Delegate, datasource to ViewController(esto es solo ViewController principal)
No use 2 celdas de plumín diferentes para 1 collectionView, porque solo puede registrar 1 plumín. Mejor uso DecorationView como headerView. Crear una nueva clase headerView: UICollectionReusableView. Este UICollectionReusableView es una subclase de UIView que puede reutilizarse dentro de UICollectionView junto con UICollectionViewCell. Ahora puedes registrar ambos tipos:
[self.collectionView registerNib:[UINib nibWithNibName:@"MyCell" bundle:nil] forCellWithReuseIdentifier:@"CELL"];
[self.collectionView registerNib:[UINib nibWithNibName:@"HeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderCell"];
A continuación, arrastra otro UICollectionView a este headerView, conéctate con IBOutlet dentro de headerView.h. Aquí, es mejor establecer Delegate, DataSource a esta clase para el control. También registre qué celda Nib usará esta collectionView. Hágalo en awakeFromNib porque usted registerNib antes
- (void)awakeFromNib{
[self.topCollectionView registerNib:[UINib nibWithNibName:@"TopCell" bundle:nil] forCellWithReuseIdentifier:@"TopCell"];
[self.topCollectionView setDataSource:self];
[self.topCollectionView setDelegate:self];
}
Funcionará bien, si almacena su fuente de datos fuera, simplemente cree otra propiedad y asígnela, luego use para devolver dentro de la fuente de datos aqui.
Si desea saber cuándo hacer clic en la celda dentro de headerView, Use un protocolo customDelegate para enviar delegado a ViewController cuando haga clic en HeaderCell.
Este es mi código, espero que entiendas y puedas aplicar tus datos aquí:
Https://github.com/lequysang/gitfiles02/blob/master/CollectionViewWithDecorationView.zip
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-22 13:42:31
Parece que tu vista delegada o colección interna está muerta (¿qué hace setWeakDelegatePointer: do?). Trate de Zombies instrumento en el simulador, debe marcar si los zombies son el caso. También establezca "Punto de interrupción de excepciones" para todas las excepciones en xCode(ayudará a su depuración cuando la aplicación se ejecuta desde xCode y no desde instrumentos). También revise su implementación -[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]
, puede estar liberando esa vista de colección interna en la reutilización.
Editar: ¿Por qué no simplemente agregar la celda de encabezado como encabezado y no la celda 0 (ejemplo de encabezado en la vista de colección aquí)? También verifique (solo para asegurarse de que no sea una razón de bloqueo) sus identificadores de reutilización cuando esté creando celdas normales para la vista de colección externa. También envíe avisos mem periódicamente al depurar en el simulador.
Además, ¿por qué usar otra vista de colección para encabezado? Puede usar algo similar a iCarousel para tal diseño.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-19 15:21:08
Puede intentar lo siguiente, desplácese por la vista principal de la colección para que el encabezado no se muestre... (aún mejor) entonces en el simulador tratar de realizar una advertencia de memoria... usando Hardware - > Simular advertencia de memoria...
Esto probablemente debería crear un reciclaje y eliminación de celdas (el uicollectionview debería destruir cualquier cosa que no sea importante en este momento... si esto sucede, el encabezado se desasignará y aún tendrá una referencia débil a él... así que cualquier cosa que hagas sucederá debido a un mal acceso... también esto es "imposible" de reproducir en el simulador debido a la falta de advertencia de memoria (solo los que se crean de manera explícita)..
La vista parece pesada, así que ¿puedes intentar hacer esto y publicar los resultados?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-20 22:36:29
Sacando nuestra "Respuesta" de los comentarios.
Lamentablemente ninguna de las respuestas ayudó. Terminé refactorizando todo y luego el problema desapareció. Incluso tuve una charla bastante detallada con un ingeniero de Apple DTS que tampoco sabía qué hacer. Así que acabamos de refactorizar. Lo sentimos: /
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 13:09:33