Swift最新版本中如何获取协议定义的所有属性?
在Swift中获取协议定义的属性并求和
当然可以实现!Swift本身是静态类型语言,没有直接内置获取协议属性列表的API,但我们可以通过两种常用方式来解决这个问题:借助Objective-C运行时,或者纯Swift的手动维护方案。下面分别详细说明:
方法一:使用Objective-C运行时(自动获取协议属性)
这种方法需要依赖Objective-C的运行时API,所以我们需要给协议和类添加@objc标记(或者让类继承NSObject),这样才能让运行时识别到协议的属性。
代码示例
import Foundation // 标记协议为@objc,让Objective-C运行时能识别 @objc protocol Foo { var a: Double { get set } var b: Double { get set } } // 类继承NSObject并遵守Foo协议 class SomeClass: NSObject, Foo { var a: Double = 1 var b: Double = 2 var c: Int = 3 } // 定义求和函数 func sumProtocolProperties<T: NSObject>(of instance: T, conformingTo targetProtocol: Protocol) -> Double { var total = 0.0 var propertyCount: UInt32 = 0 // 获取协议的所有属性列表 guard let properties = protocol_copyPropertyList(targetProtocol, &propertyCount) else { return total } // 记得释放内存,避免泄漏 defer { free(properties) } // 遍历每个属性,取值并累加 for index in 0..<Int(propertyCount) { let property = properties[index] // 获取属性名称 guard let propertyName = NSString(utf8String: property_getName(property)) as String? else { continue } // 从实例中取出属性值并累加(只处理Double类型) if let value = instance.value(forKey: propertyName) as? Double { total += value } } return total } // 使用示例 let myInstance = SomeClass() let sum = sumProtocolProperties(of: myInstance, conformingTo: Foo.self) print(sum) // 输出:3.0
优缺点
- ✅ 优点:不需要手动维护属性列表,协议属性变更时自动同步,减少出错概率
- ❌ 缺点:依赖Objective-C运行时,仅支持Objective-C兼容的类型(Swift特有的自定义结构体等无法处理),类需要继承NSObject或标记@objc
方法二:纯Swift方案(手动维护属性列表)
如果不想依赖Objective-C,我们可以给协议添加一个静态属性来维护它的所有属性名称,然后通过Mirror来从实例中读取对应的值。
代码示例
protocol Foo { var a: Double { get set } var b: Double { get set } // 静态属性:维护协议定义的所有属性名称 static var protocolPropertyNames: [String] { get } } // 扩展协议,实现静态属性 extension Foo { static var protocolPropertyNames: [String] { ["a", "b"] } } class SomeClass: Foo { var a: Double = 1 var b: Double = 2 var c: Int = 3 } // 定义求和函数 func sumProtocolProperties<T: Foo>(of instance: T) -> Double { let instanceMirror = Mirror(reflecting: instance) var total = 0.0 // 遍历协议维护的属性名称,从实例中取值累加 for propertyName in T.protocolPropertyNames { for child in instanceMirror.children { if child.label == propertyName, let value = child.value as? Double { total += value break } } } return total } // 使用示例 let myInstance = SomeClass() let sum = sumProtocolProperties(of: myInstance) print(sum) // 输出:3.0
优缺点
- ✅ 优点:完全基于Swift,支持所有Swift类型,不需要依赖Objective-C
- ❌ 缺点:需要手动维护
protocolPropertyNames列表,协议属性变更时必须同步更新这个列表,否则会出错
总的来说,如果你的场景可以兼容Objective-C,第一种方法更省心;如果需要纯Swift环境,第二种方法更灵活,只是需要多维护一个属性列表。
内容的提问来源于stack exchange,提问作者Gargoyle
相关产品推荐
相关产品推荐

