【问题标题】:Change in an instance of class type is not reflected in other reference类类型实例的变化不会反映在其他引用中
【发布时间】:2021-09-25 00:34:46
【问题描述】:

上下文

我正在使用 NSCollectionLayoutDecorationItem 和 NSCollectionLayoutSection 构建 UICollectionViewLayout。

我做的步骤是:

  1. 实例化一个NSCollectionLayoutSection,命名为section
  2. 实例化一个NSCollectionLayoutDecorationItem,命名为decoration
  3. 将装饰分配给数组 section.decorationItems
  4. 通过填充 contentInsets 来更新装饰

但是,我在第 4 步中所做的更新并未反映在 section.decorationItems 中。 (交换第 3 步和第 4 步可以解决问题,但仍然不能解释问题。)

问题

NSCollectionLayoutDecorationItem is a class, hence reference type.为什么更改没有反映在数组section.decorationItems中?我不熟悉objective-c,NSCollectionLayoutDecorationItem 是不是类似于objc 中的不可变类?

代码 sn-p

let section = NSCollectionLayoutSection(group: group) // Step 1
let decoration = NSCollectionLayoutDecorationItem.background(elementKind: Self.sectionBackgroundDecorationElementKind) // Step 2
section.decorationItems = [decoration] // Step 3
print("before change \(section.decorationItems)")
decoration.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5) // Step 4 --> change not reflected in section.decorationItems
print("after change \(section.decorationItems)") // same output as "before change"

【问题讨论】:

  • 我不能用我自己的类而不是NSCollectionLayoutSection 来重现这个。你真的可以给minimal reproducible example吗?
  • @Sweeper 感谢您的检查。到目前为止,我只在NSCollectionLayoutSection 上发现了这种行为。请参阅this gist 以获取最小的可重现示例。

标签: ios swift objective-c uicollectionviewlayout


【解决方案1】:

在您分配给section.decorationItems 的那一刻,您传入的实例会生成一个副本。所以section.decorationItems[0] 是您的decoration 的副本,但也是一个完全不同的实例。这就是为什么您对其中一个所做的更改不会影响另一个。您可以在调试器中看到这一点,因为内存地址不同。

如果您想在分配给 section.decorationItems 后更改值,您必须像 section.decorationItems[0].contentInsets = ... 一样进行操作,或者使用更新的实例重新分配给 section.decorationItems,这样它就可以制作新的副本。

UIKit 中有许多地方在您分配某个类的某个实例以提供某些配置时会生成副本。即使它是引用类型。通常文档会提到它,但NSCollectionLayoutSection 没有。

【讨论】:

  • 这个答案似乎是正确的。这似乎是调用顺序的一个不幸的副作用。文档说@NSCopying var edgeSpacing: NSCollectionLayoutEdgeSpacing? { get set } 在应用插图之前被调用。由于某种原因,这会返回一个副本,因此引用已更改。因此,原件仍将在数组中,装饰现在将是带有插图的副本。我会在分配 decoration.contentInsets = ... 后尝试打印装饰。
猜你喜欢
  • 2019-11-27
  • 1970-01-01
  • 2015-06-09
  • 2021-12-01
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
相关资源
最近更新 更多