扬庆の博客

Swift语法(1)- Mirror

字数统计: 924阅读时长: 5 min
2021/04/22 Share

Mirror 反射的用法

Mirror 是 swift 中的反射机制, 可以动态的获取类型以及成员信息, 同时也可以在运行时动态的调用方法和属性等.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// **** Mirror ****
//

class Person {
var name: String = "yangqing"
var age: Int = 27
var height: Double = 1.70
}

var p = Person()
var mirror = Mirror(reflecting: p.self)

print("对象类型: \(mirror.subjectType)")
print("对象属性个数: \(mirror.children.count)")
print("对象属性及属性值")

for child in mirror.children {
print("\(child.label!) ---- \(child.value)")
}

// **** 可以看到属性名和值都已经正常打印 ****


// 其他用法

import UIKit

// **** 开发中使用到 Mirror ****

// **** 1. 对象转换为字典 ****
class Animal {
var name: String?
var color: String?
private var birthday: Date = Date(timeIntervalSince1970: 0)
}


class Cat: Animal {
var master = "小黑"
var like: [String] = ["mouse", "fish"]
override init() {
super.init()
color = "黄色"
}

func mapDic(mirror: Mirror) -> [String : Any] {
var dic: [String : Any] = [:]
for child in mirror.children {
// 如果没有 label 就被抛弃
if let label = child.label {
let propertyMirror = Mirror(reflecting: child.value)
print(propertyMirror)
dic[label] = child.value
}
}
// 添加父类属性
if let superMirror = mirror.superclassMirror {
let superDic = mapDic(mirror: superMirror)
for p in superDic {
dic[p.key] = p.value
}
}
return dic
}

}

// Mirror 使用
let cat = Cat()
cat.name = "大橘为重"
let mirror = Mirror(reflecting: cat)
let mirrorDic = cat.mapDic(mirror: mirror)
print(mirrorDic)




// **** 转 JSON ****
struct Address {
var street: String
}

struct Person: CustomJSONProtocol {
var name: String = "yangqing"
var age: Int = 27
var isMale: Bool = true
var address: Address? = Address(street: "xizhimen North")
var height = 1.70
var like: Array = ["eat", "sleep", "play"]
var weight: Float = 75
var some: Int?
}

// ***** 创建一个person对象 *****
let p = Person()

protocol CustomJSONProtocol {
func toJSON() throws -> Any?
}

enum JSONMapError: Error {
case emptyKey
case notConformProtocol
}

extension JSONMapError: LocalizedError {
var errorDescription: String? {
switch self {
case .emptyKey:
return "key 为空"
case .notConformProtocol:
return "没遵守协议"
}
}
}

extension JSONMapError: CustomNSError {
var errorCode: Int{
switch self {
case .emptyKey:
return 100
case .notConformProtocol:
return 101
}
}
}

extension CustomJSONProtocol {

func toJSON() throws -> Any? {

let mirror = Mirror(reflecting: self)

guard !mirror.children.isEmpty else { return self }

var result: [String:Any] = [:]

for children in mirror.children {
if let value = children.value as? CustomJSONProtocol{
if let key = children.label {
print(key)
result[key] = try value.toJSON()
}else {
throw JSONMapError.emptyKey
}
}else {
throw JSONMapError.notConformProtocol
}
}
return self
}
}


let p2 = Person()

do {
print(try p.toJSON()!)
}catch {
print(error.localizedDescription)
print((error as? JSONMapError)?.errorCode)
}

struct Point {
let x: Int, y: Int
}
let p3 = Point(x: 20, y: 30)
String(reflecting: p)

autoclosure

把一句表达式自动封装成闭包 closure, 这样有时候在语法上看起爱就会非常漂亮 .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// **** autoclosure ****
func logIfTrue(_ predicate: () -> Bool) {
if predicate() {
print("True")
}
}

logIfTrue({ return 2 > 1 })
logIfTrue({ 2 > 1 })

func logIfTrue2(_ predicate: @autoclosure () -> Bool) {
if predicate() {
print("True")
}
}

logIfTrue2(2 > 1)

associatedtype

关联类型为协议中某个类型提供了一个占位符名称, 其代表的实际类型在协议被遵循时才会被指定. 关联类型通过 associatedtype 关键字来指定.

定义一个协议时, 声明一个或者多个关联类型作为协议定义的一部分将会非常有用.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import UIKit

protocol Food { }
struct Meat: Food { }
struct Grass: Food { }

protocol Animal {
associatedtype F: Food
func eat(_ food: F)
}

struct Tiger: Animal {
func eat(_ food: Meat) {
print("eat \(food)")
}
}

struct Sheep: Animal {
func eat(_ food: Grass) {
print("eat \(food)")
}
}

func isDangerous<T: Animal>(animal: T) -> Bool {
if animal is Tiger {
return true
} else {
return false
}
}

isDangerous(animal: Tiger())
isDangerous(animal: Sheep())


输出:
true
false

associate object

扩展类添加实例变量不允许的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class MyClass {

}

private var key: Void?

extension MyClass {
var title: String? {
get {
return objc_getAssociatedObject(self, &key) as? String
}
set {
objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}


// **** test ****

func printTitle(_ input: MyClass) {
if let title = input.title {
print("Title: \(title)")
}else {
print("没有设置")
}
}

let a = MyClass()
printTitle(a)

a.title = "Swifter.tips"
printTitle(a)

CATALOG
  1. 1. Mirror 反射的用法
  2. 2. autoclosure
  3. 3. associatedtype
  4. 4. associate object