使 swift 协议符合 Hashable

2024-03-13

我正兜圈子试图得到Hashable与多个人一起工作struct符合相同的protocol.

我有一个协议SomeLocation声明如下:

protocol SomeLocation {
    var name:String { get }
    var coordinates:Coordinate { get }
}

然后我创建多个包含类似数据的对象,如下所示:

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 {
        ...
    }
}

我稍后可以通过声明在同一个数组中使用它们:

let locations: [SomeLocation]

问题是,我创建了一个MKAnnotation子类并且需要使用自定义Hashable on the SomeLocation对象。

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
}

这给了我两个错误:

“SomeLocation”类型的值没有成员“hashValue”二元运算符

“==”不能应用于两个“SomeLocation”操作数

所以我添加了Hashable我的协议SomeLocation协议:

protocol SomeLocation: Hashable {
    ...
}

这消除了 hashValue 不可用的第一个错误,但现在我在声明的地方收到错误let location:SomeLocation saying

协议“SomeLocation”只能用作通用约束,因为它具有 Self 或关联的类型要求

所以看起来我不能添加Hashable到协议。

我可以添加Hashable直接到实现的每个结构体SomeLocation协议,但这意味着我需要使用这样的代码,并在每次我可能创建另一个符合协议的对象时不断更新它SomeLocation协议。

override var hash: Int {
    if let location = location as? ShopLocation
    {
        return location.hashValue
    }
    return self.hashValue
}

我尝试过另一种方法,通过制作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
    }
}

但是当我尝试在中使用它时LocationAnnotation类如

let location: SomeLocationRepresentable
init(location:SomeLocation) {
    self.location = SomeLocationRepresentable(with: location)
    super.init()
}

我收到一个错误

协议类型“SomeLocation”的值不能符合“SomeLocation”;只有 struct/enum/class 类型可以符合协议

有可能实现我想做的事情吗?使用全部符合协议的对象并使用自定义Hashable将一个与另一个进行比较?


协议源自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
    }
}

然后,您可以简单地声明结构上的协议一致性,并且如果Coordinate已经Hashable,那么你不需要编写任何额外的哈希代码代码,因为编译器可以自动为你合成(只要新类型的所有属性都是这样,那么你就不需要编写任何额外的哈希代码代码)Hashable:

struct ShopLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate
}

struct CarLocation: SomeLocation, Decodable {
    var name: String
    var coordinates: Coordinate
}

If 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
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使 swift 协议符合 Hashable 的相关文章

  • Swift 中 UIImages 的淡入淡出动画

    我有一组图像 我希望它们在登录屏幕的背景中淡出 我无法在 swift 中找到任何可以做到这一点的东西 有什么办法我可以做到吗 这是我当前的代码 override func viewDidLoad super viewDidLoad star
  • 应用未能及时恢复

    我在一个非常具体的场景中遇到 未能及时恢复 崩溃 我认为与看门狗相关 仅在从后台恢复时 并且仅在进入后台后在很短的时间内执行此操作 a最多几秒钟 这似乎是相关的崩溃日志 Incident Identifier E30F2238 5B15 4
  • 播放(非库)Apple Music 内容 - 请求失败

    我正在尝试使用以下代码播放专辑 let predicate MPMediaPropertyPredicate value 1459938538 forProperty MPMediaItemPropertyAlbumPersistentID
  • 如何使用 afnetworking 在后台上传任务

    我正在尝试使用 AFNetworking 上传大文件 并在应用程序处于后台时继续上传 我可以很好地上传文件 但是当我尝试使用后台配置时 应用程序崩溃并显示以下堆栈跟踪 异常 EXC BAD ACCESS 代码 1 地址 0x8000001f
  • 当设置 setVisibleXRangeMaximum 时,iOS-Charts X 轴值无限重复

    我正在尝试绘制一个图表 其中 x 轴是TimeIntervalY 轴是power consumption 由于每天都会有数据 因此将有太多数据无法显示 因此 我想一次显示 5 个值 我通过设置实现了这一点self chart setVisi
  • 通用类不会将委托调用转发给具体子类

    鉴于以下情况 protocol EntityType var displayString String get extension String EntityType var displayString String return self
  • Xcode MyProjectName-Bridging-Header.h 不存在

    我想开始在我的 Objective C 项目中使用 Swift 所以我添加了一个快速类 import Foundation objc class System NSObject objc func printSome println Pri
  • 访问iOS 7隐藏的UITableViewCellScrollView?

    苹果改变了UITableViewCelliOS 7 中的层次结构 使用iOS 6 1 SDK
  • IOS Coredata 兼容 IOS 9 和 ios 10

    您好 我正在开发一个适用于 IOS 10 和 9 xcode 8 的应用程序 创建新实体对象的正确方法是什么 新的IOS 10有这个代码 var newEvent Event context context 我们如何让这段代码同时适用于 I
  • 多个 ViewController(containerView?childView?viewController 的实例?)

    我需要在另一个视图之上添加一个新视图 带有 ViewController 用户与这个新视图交互了一段时间 然后我想将其删除 在旧版本的 Xcode 中 我可以将其添加为子视图 我现在收到 EXC BAD ACCESS 错误 我不希望添加的视
  • Expo 应用程序“您的应用程序正在使用广告标识符 (IDFA)”

    我正在尝试将应用程序上传到应用程序商店 每次我上传二进制文件时 苹果都会坚持认为我的应用程序正在使用广告 而我从未实现过这样的事情 我查看了文档并删除了涉及的所有代码ASIdentifier and adIdentifier我不太确定我错过
  • 删除部分(红色删除按钮),UITableViewController - iOS

    我正在尝试做一个分组的 uitableview 并且我已经激活了编辑选项 我希望用户也能够删除整个部分 而不仅仅是特定行 因此 当您单击 编辑 时 每个表格单元格左侧显示的红色减号按钮也应该显示在各个部分 部分标题左侧 有人知道如何做到这一
  • 除了使用正则表达式之外,在 Swift 中解析 HTML

    下面是我想在 Swift 中解析的 HTML 代码 td class pinyin a href rsc audio voice pinyin pz yi1 mp3 span class mpt1 y span a a href rsc a
  • 从 AF.Request 响应获取数据

    我需要使用 Alamofire 的 Post 请求调用的 json 响应中的数据 但由于某种原因我无法访问该数据 我尝试按照 Alamofire github 文档以及这篇文章进行操作从 AF 响应 JSON 获取数据 https stac
  • 实时获取 Apple Watch heartRateVariabilitySDNN 吗?

    我正在使用下面的函数来获取 heartRateVariabilitySDNN 但它只获取一次并且不能像 heartbeat 那样实时计算 func HRVstart guard let quantityType HKObjectType q
  • iOS SDK:MapKit MKPolyLine 未显示

    我试图在地图上显示多段线 但该线没有显示 我尝试了很多事情 但注意到似乎有用 我检查了核心数据函数 它正在返回数据 所以这不是问题 它必须是我在地图点创建或地图上绘制的某个地方 我猜 我确信一定是某个地方出了点小错误 但我找不到它 My c
  • 如何在 iOS 5 中使用 Embed Segue?

    iOS 6 引入了 Embed Segue 允许在 Storyboard 中使用自定义容器控制器 有没有办法在 iOS 5 上复制这个 这里的挑战是子视图控制器的视图通常要添加为父视图控制器的某些容器视图的子视图 因为你不能随机进行序列UI
  • UITableViewController 无法识别的选择器发送到实例

    当我传递一个整数时 我有一个 tableviewcontroller 和一个detailtableviewcontroller UITableViewController setSurveyNumber 无法识别的选择器发送到实例 Biza
  • NSUserDefaults、Settings.bundle 和应用程序组

    我有一个有 2 个目标的应用程序 主应用程序和 Today 扩展 为了在这些目标之间共享设置 我打开了应用程序组功能 添加了一个组group myApp com然后使用NSUserDefaults在主应用程序和今日扩展中都是如此 var d
  • 小部件配置在 macOS 上不起作用

    我为我的 iOS 应用程序制作了一个小部件 效果很好 现在我正在将其移植到我的 macOS 应用程序中 但不知何故 小部件配置不起作用 这些项目已显示 但我无法以某种方式选择它们 查看屏幕截图 但请看一下我制作的视频 https youtu

随机推荐