动态成员查找是 Swift 中的一项功能特性,可提高与 Python 或 Javascript 等动态语言的互操作性。它允许动态成员查找调用看起来像访问类型属性的常规调用:

let people = People()
let name = people.name // 像访问属性一样

name是从字典中查找的,而不是作为 People 的属性访问的。

如何使用动态成员查找?

要在你的自定义类型中使用动态成员查找,请使用 @dynamicMemberLookup标注你的类型,并实现如下方法:

subscript(dynamicMember:)

该方法接收一个String或KeyPath类型参数

我们来看看People是如何实现动态成员查找的,下面是一个demo:

@dynamicMemberLookup
struct People {
private var map = ["name": "drbox", "job": "developer"]
subscript(dynamicMember key: String) -> String {
map[key] ?? "undefine"
}
}

现在你可以像访问它的属性一样查找 People 对象的成员。

let people = People()
let name = people.name
let job = people.job

我们分析一下People是如何实现动态成员查找的

  • 首先我们使用@dynamicMemberLookup标注了People类型
  • 实现了subscript(dynamicMember:)方法,该方法我们接收一个String类型的参数,并返回一个String类型值

现在你已经了解了动态成员查找的作用以及如何实现它。让我们通过KeyPath来看看另一个有用的例子。

struct Info {
let job: String
let homeAddr: String
} struct People {
let name: String
let info: Info
} let info = Info(job: "developer", homeAddr: "beijing")
let people = People(name: "drbox", info: info)
print("job: \(people.info.job)") // 访问成员属性的属性

通过调用people.info.job可以访问Info的属性值。但是,如果你想直接通过people.job 而不是people.info.job 调用它怎么办?

这时动态成员查找的KeyPath就派上用场了。

@dynamicMemberLookup
struct People {
let name: String
let info: Info subscript<T>(dynamicMember path: KeyPath<Info, T>) -> T {
info[keyPath: path]
}
} let info = Info(job: "developer", homeAddr: "beijing")
let people = People(name: "drbox", info: info)
print("job: \(people.job)") // 直接访问成员属性的属性

以上就是我们演示如何实现动态成员查找的例子,它让people.job成为了可能。这只是一个用于讲解动态成员查找的简单案例,但在实际开发中,我们最好不要这么做。

而动态成员查找在实际项目中的运用,你可以参考RxCocoa中Reactive,它运用动态成员查找,巧妙的为任何一个AnyObject类型的对象,增加了属性的Binder观察者。

@dynamicMemberLookup
public struct Reactive<Base> {
/// Base object to extend.
public let base: Base /// Creates extensions with base object.
///
/// - parameter base: Base object.
public init(_ base: Base) {
self.base = base
} /// Automatically synthesized binder for a key path between the reactive
/// base and one of its properties
public subscript<Property>(dynamicMember keyPath: ReferenceWritableKeyPath<Base, Property>) -> Binder<Property> where Base: AnyObject {
Binder(self.base) { base, value in
base[keyPath: keyPath] = value
}
}
}

例如:绑定UIView的背景色

最新文章

  1. 对C#泛型实例化对像
  2. 认识IoC
  3. caffe的python接口学习(3):训练模型(training)
  4. Mouse.OverrideCursor
  5. DBAccess
  6. Jstat在分析java的内存GC时的应用
  7. ie浏览器兼容性快速处理小招
  8. 236. Lowest Common Ancestor of a Binary Tree
  9. OpenGL中的深度、深度缓存、深度测试及保存成图片
  10. junit initializationError和找不到或无法加载主类
  11. 学习flex布局(弹性布局)
  12. MongoDB,无模式文档型数据库简介
  13. 《Java并发编程实战》笔记-取消与关闭
  14. php 设置模式 单元素模式(单例模式或单件模式)
  15. ora-4031错误
  16. Harbor 企业级 Docker Registry
  17. PLSQL 配置连接ORACLE数据库
  18. web Servlet 3.0 新特性之web模块化编程,web-fragment.xml编写及打jar包
  19. mysql 查询近几天的结果
  20. centos安装更新Python2.7以及pip的安装

热门文章

  1. .NET Core MongoDB的简单使用
  2. 深度学习-LSTM
  3. Android:遍历视图
  4. 常用的hive sql
  5. 如何在 JavaScript 中使用媒体查询
  6. Compiler25th005: Excel Compiler
  7. 麒麟v10系统安Influxdb2.0教程
  8. mybatis动态标签——trim
  9. 【Redis的三种数据删除策略】定时定期惰性,超出内存就自动清理
  10. el-input 使用 回车键会刷新页面的问题