kingjiajie/JJCollectionViewRoundFlowLayout

切换夜间模式的问题, myCacheAttr 可能会存在空, 导致视图背景被清空

issumao opened this issue · 5 comments

  1. 切换夜间模式
  2. JJCollectionReusableView 触发 traitCollectionDidChange 时, _myCacheAttr 可能会存在空, 导致视图背景被清空
  3. 观察到的可能原因是, JJCollectionViewRoundFlowLayout 的 prepareLayout 过多的被重复调用, decorationViewAttrs 存储的值被释放, 导致 JJCollectionReusableView 的弱引用 myCacheAttr 也被释放. 在切换夜间模式时, 造成上诉情况.
  4. 可能的修复途径, 为JJCollectionViewRoundLayoutAttributes 覆写 isEqual 方法

还请复查, 并评估最优解

  1. 切换夜间模式
  2. JJCollectionReusableView 触发 traitCollectionDidChange 时, _myCacheAttr 可能会存在空, 导致视图背景被清空
  3. 观察到的可能原因是, JJCollectionViewRoundFlowLayout 的 prepareLayout 过多的被重复调用, decorationViewAttrs 存储的值被释放, 导致 JJCollectionReusableView 的弱引用 myCacheAttr 也被释放. 在切换夜间模式时, 造成上诉情况.
  4. 可能的修复途径, 为JJCollectionViewRoundLayoutAttributes 覆写 isEqual 方法

还请复查, 并评估最优解

感谢回复,我这边排查一下。

  1. 切换夜间模式
  2. JJCollectionReusableView 触发 traitCollectionDidChange 时, _myCacheAttr 可能会存在空, 导致视图背景被清空
  3. 观察到的可能原因是, JJCollectionViewRoundFlowLayout 的 prepareLayout 过多的被重复调用, decorationViewAttrs 存储的值被释放, 导致 JJCollectionReusableView 的弱引用 myCacheAttr 也被释放. 在切换夜间模式时, 造成上诉情况.
  4. 可能的修复途径, 为JJCollectionViewRoundLayoutAttributes 覆写 isEqual 方法

还请复查, 并评估最优解

您好,我在对demo进行排查,暂时没发现对应描述的问题。
我这边使用了模拟器、iPhone 15.3版本。通过进行不停的切换白天模式、夜间模式。都没出现对应问题。
您这边是否可以提供一下您出问题的情况更多描述或者demo呢?

你好, 我尝试在Demo上实现了上述现象, 采用github上直接下载的demo, 模拟器 iPhone 13, 版本 15.0, Xcode - Version 13.1.
大致模拟一下我app的一个流程. 对Demo做了以下3处修改:

  1. 在 ViewDidLoad 的尾部增加一个延时1秒的reload
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.myCollectionView reloadData];
    });

image
2. section增加, row减少

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    return 3;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return 4;
}

image

  1. didSelectItemAtIndexPath的方法里, 增加切换夜间模式的来回切换
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    [[UIApplication sharedApplication].windows enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (@available(iOS 13.0, *)) {
            obj.overrideUserInterfaceStyle = (obj.overrideUserInterfaceStyle == UIUserInterfaceStyleLight) ? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight;
        };
    }];
}

image

点击 item 来回切换夜间模式, 第一个item的背景色会丢失

你好, 我尝试在Demo上实现了上述现象, 采用github上直接下载的demo, 模拟器 iPhone 13, 版本 15.0, Xcode - Version 13.1. 大致模拟一下我app的一个流程. 对Demo做了以下3处修改:

  1. 在 ViewDidLoad 的尾部增加一个延时1秒的reload
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.myCollectionView reloadData];
    });

image 2. section增加, row减少

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
    return 3;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return 4;
}

image

  1. didSelectItemAtIndexPath的方法里, 增加切换夜间模式的来回切换
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    [[UIApplication sharedApplication].windows enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (@available(iOS 13.0, *)) {
            obj.overrideUserInterfaceStyle = (obj.overrideUserInterfaceStyle == UIUserInterfaceStyleLight) ? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight;
        };
    }];
}

image

点击 item 来回切换夜间模式, 第一个item的背景色会丢失

感谢您的反馈,我这边按照您的方案进行尝试。

  1. 切换夜间模式
  2. JJCollectionReusableView 触发 traitCollectionDidChange 时, _myCacheAttr 可能会存在空, 导致视图背景被清空
  3. 观察到的可能原因是, JJCollectionViewRoundFlowLayout 的 prepareLayout 过多的被重复调用, decorationViewAttrs 存储的值被释放, 导致 JJCollectionReusableView 的弱引用 myCacheAttr 也被释放. 在切换夜间模式时, 造成上诉情况.
  4. 可能的修复途径, 为JJCollectionViewRoundLayoutAttributes 覆写 isEqual 方法

还请复查, 并评估最优解

您好,经过各种排查和复现,在排查中感觉应该特定数据量才会出现该问题。
现在初步判断为,collectionview系统在setlayout的情况下,会对UICollectionViewLayoutAttributes进行不同程度的copy,导致前期保存下来的_myCacheAttr存在为空的情况。

现在解决方案如下:在JJCollectionViewRoundLayoutAttributes下实现NSCopying,重写JJCollectionViewRoundLayoutAttributes 的copy方法,捕获系统copy,验证后续_myCacheAttr正常。