Post

Mirror를 이용한 유연한 API Response Handling

API Response에서 action값의 유무에 따라 다른 행동을 해야한다면 init(from decoder: any Decoder) throws가 아닌 Mirror를 통해 쉽게 해결할 수 있다.

1
2
3
4
5
{
“action1”: “some action1”,
“action2”: “some action2”,
“action3”: “some action3”
}
1
2
3
4
5
struct Response: Decodable {
    let action1: String?
    let action2: String?
    let action3: String?
}
1
2
3
let decoded = JSONDecoder().decode(Response.self, from: responseData)
let mirror = Mirror(reflection: decoded)
let doAction = mirror.children.compactMap { $0.value }.first

기타

reflection APISwiftC++로 구현되어있다.

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
internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    
    let childCount = _getChildCount(subject, type: subjectType)
    let children = (0 ..< childCount).lazy.map({
      getChild(of: subject, type: subjectType, index: $0)
    })
    self.children = Children(children)
    
    self._makeSuperclassMirror = {
      guard let subjectClass = subjectType as? AnyClass,
            let superclass = _getSuperclass(subjectClass) else {
        return nil
      }
      
      // Handle custom ancestors. If we've hit the custom ancestor's subject type,
      // or descendants are suppressed, return it. Otherwise continue reflecting.
      if let customAncestor = customAncestor {
        if superclass == customAncestor.subjectType {
          return customAncestor
        }
        if customAncestor._defaultDescendantRepresentation == .suppressed {
          return customAncestor
        }
      }
      return Mirror(internalReflecting: subject,
                    subjectType: superclass,
                    customAncestor: customAncestor)
}

참고

How Mirror Works
Mirror Source
Mirror

This post is licensed under CC BY 4.0 by the author.