英文:
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
,使用了 redCellRegistration
和 blueCellRegistration
。
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.
我意识到在 redCellRegistration
和 blueCellRegistration
中创建 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
分配给 redCellRegistration
和 blueCellRegistration
中的变量。(因为 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.
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.
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
}()
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论