Dar*_*ren 6 protocols ios hashable swift swift-protocols
I'm going around in circles trying to get Hashable to work with multiple struct that conform to the same protocol.
I have a protocol SomeLocation declared like this:
protocol SomeLocation {
var name:String { get }
var coordinates:Coordinate { get }
}
Run Code Online (Sandbox Code Playgroud)
Then I create multiple objects that contain similar data like this:
struct ShopLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
init(from decoder: Decoder) throws {
...
}
}
struct CarLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
init(from decoder: Decoder) throws {
...
}
}
Run Code Online (Sandbox Code Playgroud)
I can later use these in the same array by declaring:
let locations: [SomeLocation]
Run Code Online (Sandbox Code Playgroud)
The problem is, I create an MKAnnotation subclass and need to use a custom Hashable on the SomeLocation objects.
final class LocationAnnotation:NSObject, MKAnnotation {
let location:SomeLocation
init(location:SomeLocation) {
self.location = location
super.init()
}
}
override var hash: Int {
return location.hashValue
}
override func isEqual(_ object: Any?) -> Bool {
if let annot = object as? LocationAnnotation
{
let isEqual = (annot.location == location)
return isEqual
}
return false
}
Run Code Online (Sandbox Code Playgroud)
This gives me 2 errors:
Value of type 'SomeLocation' has no member 'hashValue' Binary operator
'==' cannot be applied to two 'SomeLocation' operands
So I add the Hashable protocol to my SomeLocation protocol:
protocol SomeLocation: Hashable {
...
}
Run Code Online (Sandbox Code Playgroud)
This removes the first error of hashValue not being available, but now I get an error where I declared let location:SomeLocation saying
Protocol 'SomeLocation' can only be used as a generic constraint because it has Self or associated type requirements
So it doesn't look like I can add Hashable to the protocol.
I can add Hashable directly to each struct that implements the SomeLocation protocol, however that means I need to use code like this and keep updating it every time I might make another object that conforms to the SomeLocation protocol.
override var hash: Int {
if let location = location as? ShopLocation
{
return location.hashValue
}
return self.hashValue
}
Run Code Online (Sandbox Code Playgroud)
I have tried another way, by making a SomeLocationRepresentable struct:
struct SomeLocationRepresentable {
private let wrapped: SomeLocation
init<T:SomeLocation>(with:T) {
wrapped = with
}
}
extension SomeLocationRepresentable: SomeLocation, Hashable {
var name: String {
wrapped.name
}
var coordinates: Coordinate {
wrapped.coordinates
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(coordinates)
}
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.name == rhs.name && lhs.coordinates == rhs.coordinates
}
}
Run Code Online (Sandbox Code Playgroud)
however when I try to use this in the LocationAnnotation class like
let location: SomeLocationRepresentable
init(location:SomeLocation) {
self.location = SomeLocationRepresentable(with: location)
super.init()
}
Run Code Online (Sandbox Code Playgroud)
I get an error
Value of protocol type 'SomeLocation' cannot conform to 'SomeLocation'; only struct/enum/class types can conform to protocols
Is it possible to achieve what I am trying to do? Use objects that all conform to a protocol and use a custom Hashable to compare one to the other?
Cri*_*tik 11
从类型擦除器派生协议Hashable并使用类型擦除器可能会有所帮助:
protocol SomeLocation: Hashable {
var name: String { get }
var coordinates: Coordinate { get }
}
struct AnyLocation: SomeLocation {
let name: String
let coordinates: Coordinate
init<L: SomeLocation>(_ location: L) {
name = location.name
coordinates = location.coordinates
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以简单地声明结构上的协议一致性,如果Coordinate已经是Hashable,那么您不需要编写任何额外的哈希代码代码,因为编译器可以自动为您合成(只要满足以下条件,编译器就会自动为您合成)他们的所有属性是Hashable:
struct ShopLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
}
struct CarLocation: SomeLocation, Decodable {
var name: String
var coordinates: Coordinate
}
Run Code Online (Sandbox Code Playgroud)
如果Coordinate也是Codable,那么您也可以省略编写任何编码/解码操作的代码,编译将合成所需的方法(假设所有其他属性已经是Codable)。
然后,您可以通过转发初始化器约束在注释类中使用橡皮擦:
final class LocationAnnotation: NSObject, MKAnnotation {
let location: AnyLocation
init<L: SomeLocation>(location: L) {
self.location = AnyLocation(location)
super.init()
}
override var hash: Int {
location.hashValue
}
override func isEqual(_ object: Any?) -> Bool {
(object as? LocationAnnotation)?.location == location
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1432 次 |
| 最近记录: |