Подтвердить что ты не робот

Плохой доступ к [UICollectionView setCollectionViewLayout: анимированный:]

Я получаю странный сбой в моем UICollectionView. Сбой UICollectionView встроен в ячейку UICollectionView другого UICollectionView.

Я не могу воспроизвести проблему, похоже, иногда, если внутренний UICollectionView получает новую инициализацию, потому что внешний CollectionView перезагружает его.

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 

То, что я делаю в строке 52 в setupBSCTopnewsCollectionView,

BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init];    

(line 52) self.collectionView.collectionViewLayout = infiniteLayout;



Изменить: - [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;
    }
}

Несколько пояснений для метода вызывает там:

- (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];
}



Правка3: авария, похоже, происходит только в особых случаях. Если приложение было в фоновом режиме, но все еще в памяти, и пользователь снова открывает его. Затем он проверяет наш API для новых данных, и если он обнаружил, что что-то загрузит их и перезагрузит весь внешний collectionView. То, когда происходит авария.

Если CollectionView перезагружается во время работы приложения, не будучи в фоновом режиме в начале, все в порядке.


Чтобы сделать настройку более понятной.
4b9b3361

Ответ 1

Извлеките наш "Ответ" из комментариев.

К сожалению, ни один из ответов не помог. Я закончил реорганизацию всего этого, и проблема исчезла. У меня даже были довольно подробные разговоры с инженером Apple DTS, который также не знал, что делать. Поэтому мы просто реорганизовали. Извините:/

Ответ 2

Во-первых, перетащите UICollectionView в ViewController в XIB, подключите делегат, источник данных к ViewController (это только основной ViewController)

Не используйте 2 разных ячейки nib для 1 CollectionView, потому что вы можете зарегистрировать только 1 Nib. Лучше использовать DecorationView как HeaderView. Создайте новый класс HeaderView: UICollectionReusableView. Этот UICollectionReusableView является подклассом UIView, который может повторно использовать внутри UICollectionView вместе с UICollectionViewCell. Теперь вы можете зарегистрировать оба типа:

[self.collectionView registerNib:[UINib nibWithNibName:@"MyCell" bundle:nil] forCellWithReuseIdentifier:@"CELL"];
[self.collectionView registerNib:[UINib nibWithNibName:@"HeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderCell"];

Затем вы перетаскиваете другой UICollectionView в этот HeaderView, подключаетесь к IBOutlet внутри HeaderView.h. Здесь лучше установить для этого класса Delegate, DataSource для этого класса. Также зарегистрируйте, какую Nib Cell будет использовать этот CollectionView. Сделайте это в awakeFromNib, потому что вы зарегистрируетеNib перед

- (void)awakeFromNib{
    [self.topCollectionView registerNib:[UINib nibWithNibName:@"TopCell" bundle:nil] forCellWithReuseIdentifier:@"TopCell"];

    [self.topCollectionView setDataSource:self];
    [self.topCollectionView setDelegate:self];
}

Это будет хорошо работать, если вы храните свой источник данных снаружи, просто создайте другое свойство и назначьте его, а затем используйте для возврата внутри источника данных здесь.

Если вы хотите знать, когда нажимаете на Cell внутри headerView, используйте протокол customDelegate для отправки делегата в ViewController при нажатии HeaderCell.

Это мой код, надеюсь, вы поймете и можете применить свои данные здесь:

https://github.com/lequysang/gitfiles02/blob/master/CollectionViewWithDecorationView.zip

Ответ 3

Похоже, что ваш делегат или внутренний просмотр коллекции мертв (что делает setWeakDelegatePointer: do?). Попробуйте инструмент Zombies на симуляторе, он должен указывать, являются ли зомби. Также установите "Исключения исключений" для всех исключений в xCode (поможет вам отлаживать, когда приложение запускается с xCode, а не с инструментами). Также проверьте реализацию -[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:], это может освободить этот внутренний просмотр коллекции для повторного использования.

Изменить: Почему бы просто не добавить заголовок ячейки как заголовок, а не ячейку 0 (пример заголовка в виде коллекции здесь)? Также проверьте (просто чтобы убедиться, что это не причина сбоя) ваши идентификаторы повторного использования, когда вы создаете нормальные ячейки для внешнего вида коллекции. Также периодически отправляйте предупреждения mem при отладке на симуляторе.

Кроме того, зачем использовать другое представление коллекции для заголовка? Вы можете использовать что-то похожее на iCarousel для такого макета.

Ответ 4

Можете ли вы попробовать следующее: прокрутите главное изображение uicollectionview, чтобы заголовок не показывался... (еще лучше), затем на симуляторе попытайтесь выполнить предупреждение о памяти... с помощью Hardware- > Имитировать предупреждение о памяти...

Это, вероятно, должно привести к переработке и удалению ячеек (uicollectionview должен уничтожить все, что не важно прямо сейчас... если это произойдет, заголовок будет освобожден, и вы все равно будете иметь слабую ссылку на него... так что ничего что вы делаете это произойдет из-за плохого доступа... также это "невозможно" воспроизвести на симуляторе из-за отсутствия предупреждения о памяти (только те, которые вы создаете явным образом).

Вид выглядит тяжелым, поэтому вы можете попробовать это и опубликовать результаты?