创建一个UICellAccessory.customView实例并在多个listCell附件中使用会导致卡住

huangapple go评论70阅读模式
英文:

Creating a UICellAccessory.customView instance and using it in multiple listCell accessories causes hang

问题

I wanted to make a UI like this.
我想制作一个类似这样的用户界面。

The component of the chevron down image on the right side of the cell is the UICellAccessory that I customized. From now on, I will call this moreAccessory.
单元格右侧的下箭头图像的组件是我自定义的 UICellAccessory。从现在开始,我将称之为 moreAccessory

To make this UI, I configured the dataSource with redCellRegistration and blueCellRegistration as follows.
为了创建这个用户界面,我如下配置了 dataSource,使用了 redCellRegistrationblueCellRegistration

And I recognized that there was a duplicate code for creating moreAccessory instance in redCellRegistration and blueCellRegistration, so decided to make this accessory a single variable and use it in common.
我意识到在 redCellRegistrationblueCellRegistration 中创建 moreAccessory 实例的代码重复,因此决定将这个附件作为一个单一变量,并在通用情况下使用它。

But the code above caused hang.
但是上面的代码导致了 hang。

When looking at the Instruments tool, UICellAccessoryManager_updateAccessories:prevailingAccessories:withLayout:edge: function occupied too much weight.
在查看 Instruments 工具时,UICellAccessoryManager_updateAccessories:prevailingAccessories:withLayout:edge: 函数占用了太多资源。

The usage of CPU was 100%, and the memory usage also continued to go up.
CPU 的使用率达到了100%,内存使用量也持续增加。

However, if I create and use an accessory through a function that returns moreAccessory, there was no error in this situation.
然而,如果通过返回 moreAccessory 的函数创建和使用附件,那么在这种情况下没有错误。

I thought, "Well, was it a problem to use the same instance?". And assigned moreAccessory to the variables in redCellRegistration and blueCellRegistration separately. (Because the UICellAccessory is struct, if I assign it to a variable, the instance will be copied.)
我想,“嗯,使用相同的实例是不是有问题呢?” 然后分别将 moreAccessory 分配给 redCellRegistrationblueCellRegistration 中的变量。(因为 UICellAccessory 是一个结构体,如果将它分配给一个变量,实例将被复制。)

However, there was an error at this time, too.
然而,在这个时候也出现了错误。

And If I make moreAccessory as a predefined accessory such as disclosureIndicator, not customView, there was no error.
如果将 moreAccessory 设定为预定义的附件,比如 disclosureIndicator,而不是 customView,那么就不会出错。

Is there anything to get a clue about this error situation?
是否有任何线索可以解决这个错误情况?

英文:

I wanted to make a UI like this.

创建一个UICellAccessory.customView实例并在多个listCell附件中使用会导致卡住

The component of the chevron down image on the right side of the cell is the UICellAccessory that I customized. From now on, I will call this moreAccessory.

To make this UI, I configured the dataSource with redCellRegistration and blueCellRegistration as follows.

let redCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .red
    cell.contentConfiguration = content
    let image = UIImageView(image: UIImage(systemName: "chevron.down"))
    let configuration = UICellAccessory.CustomViewConfiguration(customView: image,
                                                                placement: .trailing(),
                                                                tintColor: .systemGray)
    let moreAccessory = UICellAccessory.customView(configuration: configuration)
    cell.accessories = [moreAccessory]
}

let blueCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .blue
    cell.contentConfiguration = content
    let image = UIImageView(image: UIImage(systemName: "chevron.down"))
    let configuration = UICellAccessory.CustomViewConfiguration(customView: image,
                                                                placement: .trailing(),
                                                                tintColor: .systemGray)
    let moreAccessory = UICellAccessory.customView(configuration: configuration)
    cell.accessories = [moreAccessory]
}

dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) {
    (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
    
    if indexPath.row.isMultiple(of: 2) {
        return collectionView.dequeueConfiguredReusableCell(using: redCellRegistration, for: indexPath, item: identifier)
    } else {
        return collectionView.dequeueConfiguredReusableCell(using: blueCellRegistration, for: indexPath, item: identifier)
    }
}

And I recognized that there was a duplicate code for creating moreAccessory instance in redCellRegistration and blueCellRegistration, so decided to make this accessory a single variable and use it in common.

let moreAccessory: UICellAccessory = {
    let image = UIImageView(image: UIImage(systemName: "chevron.down"))
    let configuration = UICellAccessory.CustomViewConfiguration(customView: image,
                                                                placement: .trailing(),
                                                                tintColor: .systemGray)
    let accessory = UICellAccessory.customView(configuration: configuration)
    return accessory
}()


let redCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .red
    cell.contentConfiguration = content
    cell.accessories = [moreAccessory]
}

let blueCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .blue
    cell.contentConfiguration = content
    cell.accessories = [moreAccessory]
}

But the code above caused hang.

When looking at the Instruments tool, UICellAccessoryManager_updateAccessories:prevailingAccessories:withLayout:edge: function occupied too much weight.

创建一个UICellAccessory.customView实例并在多个listCell附件中使用会导致卡住

The usage of cpu was 100%, and the memory usage also continued to go up.

However, if I create and use an accessory through a function that returns moreAccessory, there was no error in this situation.

func moreAccessory() -> UICellAccessory {
    let image = UIImageView(image: UIImage(systemName: "chevron.down"))
    let configuration = UICellAccessory.CustomViewConfiguration(customView: image,
                                                                placement: .trailing(),
                                                                tintColor: .systemGray)
    let accessory = UICellAccessory.customView(configuration: configuration)
    return accessory
}

let redCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .red
    cell.contentConfiguration = content
    cell.accessories = [moreAccessory()]
}

let blueCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .blue
    cell.contentConfiguration = content
    cell.accessories = [moreAccessory()]
}

I thought, "Well, was it a problem to use the same instance?". And assigned moreAccessory to the variables in redCellRegistration and blueCellRegistration separately. (Because the UICellAccessory is struct, if I assign it to a variable, the instance will be copied.)


let moreAccessory: UICellAccessory = {
    let image = UIImageView(image: UIImage(systemName: "chevron.down"))
    let configuration = UICellAccessory.CustomViewConfiguration(customView: image,
                                                                placement: .trailing(),
                                                                tintColor: .systemGray)
    let accessory = UICellAccessory.customView(configuration: configuration)
    return accessory
}()

let redCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .red
    cell.contentConfiguration = content
    let redCellAccessory = moreAccessory
    cell.accessories = [redCellAccessory]
}

let blueCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, item) in
    var content = cell.defaultContentConfiguration()
    content.text = "\(item)"
    content.textProperties.color = .blue
    cell.contentConfiguration = content
    let blueCellAccessory = moreAccessory
    cell.accessories = [blueCellAccessory]
}

However, there was an error at this time, too.

And If I make moreAccessory as a predefined accessory such as disclosureIndicator, not customView, there was no error.

let moreAccessory: UICellAccessory = {
    let accessory = UICellAccessory.disclosureIndicator()
    return accessory
}()

创建一个UICellAccessory.customView实例并在多个listCell附件中使用会导致卡住
Is there anything to get a clue about this error situation?

答案1

得分: 2

UICellAccessory 是一个结构体,但在创建自定义附件时包含在其中的 UIView 子类是一个类。当复制结构体时,将使用相同的视图实例;不会创建新的视图。你不能在单元格之间共享相同的自定义视图(例如 UIImageView)。

你已经找到了正确的解决方案:如果你使用自定义视图,需要为每个单独的行创建一个新的 UICellAccessory 实例。你的原始代码有效,但为了避免重复,你可以使用一个工厂方法来创建新的单元格附件。另一个解决方案是在每次调用时创建一个新实例,因此它也有效。

英文:

UICellAccessory is a struct, but the UIView subclass it contains when creating a custom accessory is a class. When the struct is copied, the same view instance will be used; a new view will not be created. You cannot share the same single custom view (a UIImageView in your example) between cells.

You have already found the correct solution: you need to make a new instance of UICellAccessory for every separate row if you are using a custom view. Your original code worked, but to avoid the duplication you can have a factory method to create a new cell accessory. That was your other solution that worked because it was creating a new instance each time it was called.

huangapple
  • 本文由 发表于 2023年3月15日 21:35:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/75745461.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定