为类创建通用委托

2024-02-08

假设我有非常简单的课程:

class Box<T> {
  var boxedObject:T

  init(object: T) {
    self.boxedObject = object
  }
}

我现在想要实现的是添加委托,它可以通知我框中的值已更改:

protocol BoxDelegate<T>: class {
    func valueInBoxChanged(box: Box<T>) -> Void
}

class Box<T> {
    var boxedObject: T {
        didSet {
            self.delegate?.valueInBoxChanged(self)
        }
    }
    weak var delegate: BoxDelegate<T>?

    init(object: T) {
        self.boxedObject = object
    }
}

这段代码当然不起作用,因为我们没有通用委托。我可以使委托成为一个带有闭包的结构,但这是一个有点丑陋的解决方案。我应该如何在 Swift 中做这样的事情?


可以说,而不是BoxDelegate你有一堂课,我们就称它为Listener :

public typealias ValueChanged <T> = (T) -> Void
public class Listener<T> {
    var valueChanged: ValueChanged<T>

    public init(_ valueChanged: @escaping ValueChanged<T>) {
        self.valueChanged = valueChanged
    }
}

Box现在可以这样写:

class Box<T> {
    // the listener needs to be weak in order to be deallocated when the that is
    // observing the changes is deallocated
    weak private(set) var listener: Listener<T>?
    init(_ listener: Listener<T>) {
        self.listener = listener
    }
}

现在您可以为需要观察其状态的属性提供一个包装类:

class Observed<T> {
    var listeners: [Box<T>] = []
    private let queue: DispatchQueue = .main
    var value: T {
        didSet {
            notifyListeners()
        }
    }
    func notifyListeners() {
        notifyListeners(value)
    }
    
    func notifyListeners(_ value: T) {
        queue.async { [weak self] in
            self?.listeners.forEach { (box) in
                box.listener?.valueChanged(value)
            }
        }
    }
    func bind(_ listener: Listener<T>) {
        listeners.append(Box(listener))
    }
    
    func bind(_ listener: @escaping ValueChanged<T>) -> Listener<T> {
        let listener = Listener(listener)
        listeners.append(Box(listener))
        return listener
    }
    init(_ value: T) {
        self.value = value
    }
}

甚至还有一个属性包装器:

@propertyWrapper
struct Bind<T> {
    let observable: Observed<T>
    init(wrappedValue: T) {
        observable = Observed(wrappedValue)
    }
    
    var wrappedValue: T {
        get {
            observable.value
        }
        set {
            observable.value = newValue
        }
    }
    
    var projectedValue: Observed<T> {
        observable
    }
}

usage :

var text = ""
class ViewModel {
    @Bind
    var isOn: Bool = false
}

let viewModel = ViewModel()

let bond = viewModel.$isOn.bind { isOn in
    if isOn {
        text = "on"
    } else {
        text = "off"
    }
    
}
viewModel.isOn = true
RunLoop.main.run(until: Date().advanced(by: 0.1))
text
viewModel.isOn = false
RunLoop.main.run(until: Date().advanced(by: 0.1))
text
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为类创建通用委托 的相关文章

  • 如何组合两个 SwiftyJSON 对象

    我有一个 swiftyJSON 对象 例如 location http img http commentCount 0 timestamp 1432460217550 我希望能够向其附加另一个 swiftyJSON 对象 使其看起来像 lo
  • 是否可以更改枚举中的关联值?

    我正在使用 Swift 枚举 想知道是否有一种方法可以更改枚举的关联值 例如下面的代码尝试但失败了 enum myEnum case SomeCase Int mutating func someFunc switch self case
  • 针对 iOS 10.3 进行编译,但模块“SwiftUICharts”的最低部署目标为 iOS 13.0

    知道如何仅在 iOS 版本超过 iOS 13 时导入 SwiftUICharts 框架吗 我通过 文件 gt Swift 包 gt 添加包依赖项 添加了此框架 我的应用程序目标必须是 iOS 10 我将此框架导入到 swiftui 控制器中
  • 循环多个 UIAlertController

    在某些情况下 我的应用程序需要显示多个警报消息 错误消息在启动时收集 并且需要一次向用户显示一条 当第一个被确认后 应该呈现下一个 问题在于 显然 它们都试图同时执行 有没有一种聪明的方法可以同步执行此操作 这是一些简单描述我想要做的事情的
  • XCode 7 中的 AWSS3TransferManagerUploadRequest

    我今天升级到 Xcode 7 Swift 2 0 我的项目正在使用 CocoaPods 我正在 POD 文件中导入所有与 AWS 相关的文件 我已经设置了桥接标头 并导入了 Amazon 告诉我的所有文件 在升级到 Swift 2 0 之前
  • iOS Swift 和 reloadRowsAtIndexPaths 编译错误

    我与 xCode Swift 陷入僵局并刷新 UITableView 的单行 这条线有效 self tableView reloadData 而这条线没有 self tableView reloadRowsAtIndexPaths curr
  • 检查 Swift 中关联类型是否符合协议

    在类似情况下 如何检查对象是否符合 可表示 协议 protocol Representable associatedtype RepresentType var representType RepresentType get set cla
  • WKWebview 中的 iCLoud 文档选择器关闭容器视图

    我有一个 WKWebview 加载基于 Web 的 UI 我希望用户能够从其 iCloud 文档上传文件 我已授予正确的权限 并且可以浏览 iCloud 文档 但是 当我选择文件或单击取消按钮时 文档选择器视图也会关闭 WKWebview
  • 如何在 Swift 中使用未知密钥解码 JSON 响应?

    我想将数据拆分为https blockchain info ticker https blockchain info ticker这样每一行都是它自己的String在一个数组中 我正在制作一个获取所选货币价格的应用程序 因此 如果有人想要澳
  • 具有动态警报正文的快速本地通知

    所以我可以创建一个像这样的本地通知 var localNotification UILocalNotification localNotification fireDate NSDate timeIntervalSinceNow 7 loc
  • 如何检测 swiftui 中是否存在键盘

    我想知道按下按钮时键盘是否存在 我该怎么做 我已经尝试过 但我没有任何运气 谢谢 使用该协议 KeyboardReadable 你可以符合任何View并从中获取键盘更新 KeyboardReadable协议 import Combine i
  • 删除派生数据文件夹后,Xcode 不断重新创建派生数据文件夹

    自动完成功能在 Xcode 6 中不再起作用 我四处搜索 发现删除派生数据文件夹可以解决此问题 每次我删除它时 它都会回来 然后就不会再自动完成了 有什么建议么 Thanks 没关系 我解决了这个问题 我没有声明需要在类内的方法中使用的变量
  • Swift 中的柯里函数

    我想创建一个返回柯里函数的函数 如下所示 func addTwoNumbers a Int b Int gt Int return a b addTwoNumbers 4 b 6 Result 10 var add4 addTwoNumbe
  • iOS 防止计时器 UILabel 在数字变化时“晃动”

    我有一个UILabel它以以下格式显示计时器的输出MM ss SS 分 秒 厘秒 但是随着厘秒宽度的变化 它从左向右 摇动 例如 11 比 33 窄 有什么办法可以减轻这种情况吗 我尝试过将其居中 给它固定的宽度 但它们似乎没有帮助 从iO
  • 设置/覆盖 UICollectionView 中单元格之间的填充

    我有一个 UICollectionView 但在获取单元格之间的填充时遇到了问题 理论上 我应该能够将屏幕除以 4 并且我可以获得包含 4 个图像的单元格大小 完美地占据屏幕宽度 但是 它选择不这样做 相反 它会创建 3 个具有巨大填充的图
  • Swift:如何减少 didupdatelocations 调用

    我想出了一些代码来打印我所在位置的地址和邮政编码 这是在 didupdatelocation 函数中完成的 我遇到的唯一问题是 didupdatelocation 函数每秒都会更新该地址 因为这电池效率非常低 所以我一直在寻找使用间隔的方法
  • 在 SwiftUI 中使用分段式选取器在两个页面之间滑动

    我有一个Picker with pickerStyle SegmentedPickerStyle 使其成为分段控件 我想让页面在之间平滑滑动 而不是使用条件语句替换视图 这是我迄今为止所做的 gif 这是到目前为止的代码 由if 而不是在不
  • 如何在 Swift 中获取字典中最后输入的值?

    如何获取 Swift 字典中最后输入的值 例如 我如何从下面获取值 CCC var dictionary Dictionary
  • 在真实设备上展示测试广告

    这是我的代码 let request GADRequest request testDevices kGADSimulatorID XXXX2F32d69CCA859FFB559D0FEA3CF6483D08A6 adView load r
  • NVActivityIndi​​catorView 仅适用于特定视图

    我正在使用这个库https github com ninjaprox NVActivityIndi catorView https github com ninjaprox NVActivityIndicatorView用于显示加载指示器

随机推荐

  • 窗口服务的通知图标

    我开发了 win 服务程序 它从本地驱动器读取 Excel 文件 然后将此文件值保存到数据库 现在我想开发一个通知图标 该图标将在之后显示一条消息 Excel 文件已保存在数据库中 我的服务将启动并将 Excel 文件保存到数据库 请给我一
  • 绑定到 TabControl SelectedIndex

    我在页面上有一个选项卡控件 它的项目绑定回我的 ViewModel 它还公开了一个 ActiveTabItemIndex 它绑定 两种方式 到我的 xaml 中的 SelectedIndex 属性 并实现 INotifyPropertyCh
  • 设置闹钟不工作

    我正在使用一个IntentService准备警报并使用setAlarmClock在其中设置闹钟 这IntentService始终在正确的时间运行并设置警报 将显示图标 但警报将工作 100 次中的 99 次 当一个警报失败时 每个警报都会出
  • 新类不显示在参考对象浏览器中

    我在我的类库中添加了一个新类Domain called SongPlayDaily cs但由于某种原因 它没有显示在我的参考对象浏览器中 查看图像和相关数字 观察到新班级存在于我的Domain类库 看到我在我的中引用了这个类库Unearth
  • 具有多个不同类型的 ConfigurationElement 的 ConfigurationElementCollection

    是否可以拥有一个包含许多不同类型的集合元素的 Collection ElementCollection 例如
  • Python中按相同属性对对象列表进行分组和求和的最简洁方法是什么

    我有一个 C 类型的对象列表 其中 C 类型由属性 X Y Z 组成 例如 c X c Y c Z 现在我想执行以下任务 对属性 Y 具有相同值的那些对象的属性 Z 进行求和 输出元组列表 Y 与此 Y 的 Z 之和 最简洁的方法是什么 T
  • 为什么静态字段(不是final)在java的内部类中受到限制[重复]

    这个问题在这里已经有答案了 可能的重复 为什么Java禁止内部类中的静态字段 https stackoverflow com questions 1953530 why does java prohibit static fields in
  • 是否可以查看 Eclipse 正在执行哪些 shell 命令?

    我正在处理一个相当长的项目 它需要旧的 JDK 才能正确编译 需要各种 JAR 包含等 我正在使用批处理脚本组装整个项目 并且我希望使用该脚本使整个过程完全自动化 所以我想知道是否可以查看 Eclipse 执行的 shell 命令 将一段特
  • 在添加/删除 ENV 变量时,Elastic Beanstalk 导致我的 Rails 6 应用程序预编译资产损坏

    我可以使代码部署没有问题 一切正常 问题是当我使用 Elastic Beanstalk Web 配置表单或 EB CLI 添加 删除 修改 ENV 变量时 Elastic Beanstalk 报告更改已成功完成 但是当我在浏览器中访问 We
  • 对于使用`type()`构造的类型,mypy“作为类型无效”

    mypy 抱怨error Variable packagename Foo is not valid as a type Foo type Foo Bar Optional Foo 可以通过将类型定义为类来修复此错误 class Foo p
  • php var_dump($object) 或 print_r($object) 到日志文件

    这个问题是通用的 我只是想知道如何将对象转储到日志文件 为了澄清事情 我通过一个例子来阐述 我已经成功地使用 magento 观察者在某些事件发生时调用方法 例如 我正在观察何时通过以下方式保存货件
  • Google 脚本和 AWS SDK

    我想通过 GoogleScript 中的代码与 Google Sheet 中的 Amazon Web Services DynamoDB 进行交互 但是 我不知道如何集成AWS SDK 我希望避免编写一个库来通过 AWS HTTP API
  • python中水平方向的物理拉伸图

    我想要一个使用 matplotlib 创建的简单 x y 图 并在 x 方向上进行物理拉伸 目的是获得让我更容易检测信号中的特征的结果 所以我不想改变任何尺度 值或限制 只需更改输出文件中两个网格点之间的距离 我想在四个子图上这样做 之后它
  • 使用 Pandas groupby 连接多行字符串并从逗号分隔的单元格中删除重复项

    我有以下数据并尝试按唯一 id 进行聚合 并且需要在各自列的一个单元格中获取唯一名称 唯一产品 唯一价格 Unique id Name Product Price 101 ABC Ltd A 100 102 JKL Ltd B 200 10
  • Pygame 的基本网络

    我需要为 Pygame 项目做一些基本的网络工作 基本上 它是一款 2D 单人或合作游戏 网络只需要支持两个玩家 其中一个作为主机 唯一需要发送的信息是玩家 小兵和子弹的位置 我一直在阅读并Twisted https en wikipedi
  • 使用指向本地 p2 存储库的 tycho 构建本地 eclipse 插件

    我正在创建一些需要第三方插件和功能的 Eclipse 插件和功能 为了将这些依赖项包含到我的项目中 我创建了一个 p2 布局存储库 注意 我的 p2 工件不是 Maven 项目 但是 我正在使用 Maven 风格构建 这是 p2 存储库的
  • 如何在 Nuxt 中设置 SASS/SCSS/sass-loader

    我有一个 Nuxt 应用程序 我想使用 CSS 预处理器 我安装了sass loader纤维依赖性 但安装后 应用程序控制台中会出现一条消息 我在图像和代码中显示了该消息 这是代码错误 WARN email protected cdn cg
  • 双线性插值 - DirectX 与 GDI+

    我有一个 C 应用程序 我为其编写了 GDI 代码 该代码使用 Bitmap TextureBrush 渲染来呈现 2D 图像 可以应用各种图像处理函数 该代码是应用程序中模仿现有 DX9 代码的新路径 它们共享一个公共库来执行所有向量和矩
  • 开源 SharePoint? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有 SharePoint 的开源替代品吗 我想要提供与 SharePoint 相同的层次结构和基于 p
  • 为类创建通用委托

    假设我有非常简单的课程 class Box