Как я могу заставить CMTime соответствовать Hashable на всех версиях iOS?
В Xcode 14 Apple добавила соответствие Hashable иCMTimeRange
только для iOS16. Я пытаюсь сделать его Hashable для всех версий iOS, потому что у нас есть много структур Hashable, которые содержат , и они также зависят от того, являются ли они Hashable.
До сих пор у нас было расширение, которое соответствовало Hashable, но в Xcode 14 это расширение вызывает ошибку компиляции с этим описанием:
Protocol 'Hashable' requires 'hashValue' to be available in iOS 14.0.0 and newer
Если я реализую так:
public var hashValue: Int {
var hasher = Hasher()
hash(into: &hasher)
return hasher.finalize()
}
Он компилируется и работает, но я не уверен, что это безопасно, потому чтоhashValue
устарела, поэтому я не уверен, что понимаю, зачем это нужно (толькоhash(into:)
должны быть реализованы для соответствия Hashable в наши дни).
Может ли кто-нибудь пролить свет на то, безопасно ли это решение или есть какое-либо другое решение?
Еще одна идея, которую я пробовал:
Я добавил это расширение на:
extension CMTime {
struct Hashed: Hashable {
private let time: CMTime
init(time: CMTime) {
self.time = time
}
public func hash(into hasher: inout Hasher) {
// pre iOS16 hash computation goes here.
}
}
func asHashable() -> Hashed {
return Hashed(time: self)
}
}
Затем я изменил все структуры Hashable, содержащиеCMTime
из этого:
struct Foo: Hashable {
let time: CMTime
let string: String
}
к этому:
struct Foo: Hashable {
let time: CMTime
let string: String
func hash(into hasher: inout Hasher) {
if #available(iOS 16, *) {
hasher.combine(self.time)
} else {
hasher.combine(self.time.asHashable())
}
hasher.combine(self.string)
}
}
Я не фанат этого, так как он внесет МНОГО изменений в код.
1 ответ
РЕДАКТИРОВАТЬ 2:
Приведенный ниже код работает с симулятором iOS 16, но дает сбой с iOS 15 и более ранними версиями. Странно, так как он компилируется.
Я предлагаю реализовать расширение и сделать его доступным только для iOS 15 и ниже:
@available(iOS, obsoleted: 16)
extension CMTime: Hashable {
public var hashValue: Int {
var hasher = Hasher()
hash(into: &hasher)
return hasher.finalize()
}
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
hasher.combine(timescale)
// more if needed
}
}
Что касается того, почемуhashValue
все еще нужен, я согласен, что его там не должно быть. Возможно, это ложная тревога XCode, ошибка действительно сбивает с толку. Обратите внимание, что Apple не говорит, когда он устарел, а также он устарел как требование, я предполагаю, что он все еще за кулисами: https://developer.apple.com/documentation/swift/hashable/hashvalue
РЕДАКТИРОВАТЬ 1:
CMTime
уже соответствуетHashable
. Протестировано с iOS 13, 14, 15 и 16. Я не думаю, что вам нужно ваше расширение.
import Foundation
import AVFoundation
struct Foo: Hashable {
let aaa: String
let bbb: Int
let time: CMTime
}
func testMyFoo() {
let foo1 = Foo(
aaa: "yo",
bbb: 123,
time: CMTime(
value: 100,
timescale: 1
)
)
let foo2 = Foo(
aaa: "yo",
bbb: 123,
time: CMTime(
value: 100,
timescale: 1
)
)
var myFoos = Set<Foo>()
myFoos.insert(foo1)
myFoos.insert(foo2)
print(myFoos)
// you will only have 1 foo in the Set, because they are the same.
// if you change the CMTime values in foo1, you will have 2 items in the Set.
}