You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:35:04