我刚刚更新到 Xcode 16,由于将
AnyHashable
标记为不可发送,我的项目充满了警告。我在整个应用程序中依赖 AnyHashable,创建一个返回 UITableViewDiffableDataSource<Int, AnyHashable>
类型数据源的 ViewModel 层。现在我正在尝试构建一些可哈希和可发送的东西,并且可以在没有太多重构的情况下插入。参考网上的其他示例,我创建了这个以 AnyHashable 为模型的新结构
public struct AnyHashableSendable: Hashable, Sendable {
public let base: any Hashable & Sendable
public init<H>(_ base: H) where H : Hashable {
self.base = base
}
public static func == (lhs: Self, rhs: Self) -> Bool {
AnyHashable(lhs.base) == AnyHashable(rhs.base)
}
public func hash(into hasher: inout Hasher) {
base.hash(into: &hasher)
}
}
但是当前的实现带来了一些烦恼,我希望以与苹果实现相匹配的方式解决这些烦恼
如果我有一个类型为
foo
的变量 AnyHashable
并且我想转换它,我可以简单地执行 let newBar = foo as? bar
。但是对于类型为 AnyHashableSendable
的变量,我现在必须调用属性 base
来实现相同的目的,就像这样 let newBar = foo.base as? bar
一样。内置的 AnyHashable 如何避免调用其 base
属性?
如果我定义 AnyHashable 的数组或二维数组(
[AnyHashable]
,[[AnyHashable]]
),我可以附加任何符合 hashable 的结构,它会自动转换它。例如
var array: [AnyHashable] = []
array.append(FooBar(prop1: "test", prop2: "test"))
但是对于 AnyHashableSendable,每个项目都必须初始化为新的对象类型,例如
var array: [AnyHashableSendable] = []
array.append(.init(FooBar(prop1: "test", prop2: "test")))
我尝试通过创建自己的自定义集合类型来解决至少第二个问题,并使用接受 AnyHashable 的重写函数并简单地调用 init 并存储它。虽然它有效,但差异需要大量的重构,并且也使用烦人的自定义代码/类型而不是现有逻辑。有没有一种我不知道的方法可以解决这两个问题,以便我的新类型像现有的 AnyHashable 一样运行?
您无法自己创建这样的类型。您提到的两种行为(直接向下转型和隐式转换为
AnyHashable
)都直接内置于编译器中。
根据 Swift GitHub 存储库中有关动态转换的 文档,
AnyHashable
在转换上下文中的行为类似于存在类型,尽管它是 struct
。强制转换运算符可以“到达”存在的“盒子”内部并获取其中包含的实际值。
您可以在
DynamicCast.cpp中找到
AnyHashable
的特殊情况,有对_swift_anyHashableDownCastConditionalIndirect
的调用。这个函数是“伸手到盒子里”发生的地方。请参阅 AnyHashable.swift. 中的声明。
对于到
AnyHashable
的隐式转换,编译器插入一个名为 _convertToAnyHashable
的编译器内部函数,该函数也在 AnyHashable.swift 中声明,我认为 this 是发出它的行。