Swift 中的 Mirror 类型,它是 Swift 提供的反射机制核心工具,核心作用是在运行时获取任意对象的结构信息(比如属性名、属性值、类型、继承关系等),即使你不知道对象的具体类型,也能通过 Mirror 解析它的内部结构。
一、核心概念
Mirror 就像一个 “运行时结构解析器”:
- 基于反射(Reflection) 机制,突破 Swift 静态类型的限制,在运行时探索对象的结构;
- 可解析的信息包括:对象的类型、属性(名称 + 值 + 类型)、是否是集合 / 枚举 / 类 / 结构体、继承的父类等;
- 核心 API:
Mirror(reflecting: 目标对象)—— 创建一个 Mirror 实例,用于解析目标对象; - 无侵入性:无需修改目标类型的代码,即可解析其结构。
二、基础用法
1. 基本语法
// 1. 创建 Mirror 实例(传入要解析的对象)
let targetObject = SomeType()
let mirror = Mirror(reflecting: targetObject)
// 2. 遍历 Mirror 的子节点(即对象的属性/元素)
for case let (label?, value) in mirror.children {
// label:属性名(可选值,集合元素的label为nil)
// value:属性值(类型为Any,需手动类型转换)
print("属性名:(label),值:(value),类型:(type(of: value))")
}
// 3. 获取对象的基本信息
print("对象类型:(mirror.subjectType)") // 目标对象的类型(如 LevelIcon.Type)
print("是否是集合:(mirror.displayStyle == .collection)") // 判断类型类别
2. 核心属性 / 方法说明
| 属性 / 方法 | 作用 |
|---|---|
children | 子节点集合(属性 / 元素),类型为 AnyCollection<Mirror.Child> |
subjectType | 目标对象的类型(Any.Type) |
displayStyle | 对象的类型类别(枚举值:.struct/.class/.enum/.collection等) |
superclassMirror | 父类的 Mirror(仅类对象有,结构体 / 枚举为 nil) |
三、实战示例
1. 解析结构体
struct LevelIcon{
let type: String
let url: String
let priority: Int
let isVip: Bool = true
}
// 封装的Mirror 解析模型
func parseModel<T>(_ model: T){
let mirror = Mirror(reflecting: model)
print("===== 解析 \(mirror.subjectType) 模型 =====")
for item in mirror.children {
print("属性名:\(item.label)= value:\(item.value)")
}
print("获取类型 \(mirror.displayStyle)")
// 判断模型类型
if mirror.displayStyle == .struct {
print("该对象是结构体类型")
}
}
// 创建模型对象
let nobleIcon = LevelIcon(type: "noble", url: "noble_icon.png", priority: 1)
//调用
parseModel(nobleIcon)
//结果
===== 解析 LevelIcon 模型 =====
属性名:Optional("type")= value:noble
属性名:Optional("url")= value:noble_icon.png
属性名:Optional("priority")= value:1
属性名:Optional("isVip")= value:true
获取类型 Optional(Swift.Mirror.DisplayStyle.struct)
该对象是结构体类型
2、解析数组 / 集合
let iconUrs = ["noble_icon.webp", "svip_icon.webp", "wealth_icon.webp"]
let collectionMirror = Mirror(reflecting: iconUrs)
print("集合类型:\(collectionMirror.subjectType)")
print("是否是集合:\(collectionMirror.displayStyle == .collection)")
for (index,value) in collectionMirror.children.enumerated() {
print("索引\(index) = \(value.label) - \(value.value)")
}
//结果
集合类型:Array<String>
是否是集合:true
索引0 = nil - noble_icon.webp
索引1 = nil - svip_icon.webp
索引2 = nil - wealth_icon.webp
3、解析类对象(含父类属性)
如果你的模型是类(Class),Mirror 还能解析父类的属性
// 子类
class VipLevel: BaseLevel {
let vipExp: Int = 1000
let iconUrl: String = "vip_icon.webp"
}
// 解析子类(含父类属性)
func parseClassWithSuper<T>(_ object: T) {
var currentMirror: Mirror? = Mirror(reflecting: object)
// 循环解析自身 + 父类属性
while let mirror = currentMirror {
print("===== 解析 \(mirror.subjectType) =====")
for case let (label?, value) in mirror.children {
print("属性:\(label) = \(value)")
}
// 切换到父类的 Mirror
currentMirror = mirror.superclassMirror
}
}
// 调用
let vip = VipLevel()
parseClassWithSuper(vip)
===== 解析 VipLevel =====
属性:vipExp = 1000
属性:iconUrl = vip_icon.webp
===== 解析 BaseLevel =====
属性:id = 0
属性:name = 基础等级
四、关键注意事项(避坑)
1. 私有属性无法解析
Mirror 只能解析公开(public/internal) 的属性,私有(private/fileprivate)属性不会出现在 children 中:
struct Test {
public let pubProp = "公开属性"
private let priProp = "私有属性"
}
let mirror = Mirror(reflecting: Test())
for child in mirror.children {
print(child.label!) // 仅输出:pubProp(私有属性被忽略)
}
2. 值类型转换需谨慎
Mirror 的 value 是 Any 类型,强制类型转换(as!)可能崩溃,需用可选绑定(as?):
// 错误示例:强制转换非字符串类型会崩溃
// let str = child.value as! String
// 正确示例:安全转换
if let str = child.value as? String {
// 处理字符串
} else if let int = child.value as? Int {
// 处理整数
}
3. 集合 / 枚举的解析特点
- 集合(数组 / 字典 / Set)的
children是其元素,但label为nil,需通过enumerated()手动加索引; - 枚举的
displayStyle为.enum,若枚举带关联值,children会包含关联值(label 为关联值名称)。
4. 性能注意
反射是运行时操作,性能远低于静态代码,不要在高频场景(如循环遍历上万条数据) 中使用,适合工具类场景(日志、序列化)。