# Mirror.handleChildren()

{% hint style="info" %}
<mark style="color:red;">**recursive reflections**</mark>: inspect/manipulate on children's children.
{% endhint %}

{% tabs %}
{% tab title="🌀 Mirror" %}
💾 程式： [replit](https://replit.com/@pegasusroe/Recursive-Reflection#handleChildren.swift)   &#x20;

```swift
//     *: born,  +: new,  /: update
// ─────────────────────────────────────
// 2022.01.27 * (v.1) + handleChildren
// 2022.01.28 / handleChildren: global func -> Mirror method

extension Mirror {
    /// ⭐ handle children of type T
    public static func handleChildren<T>(         // T: child's type ⭐ 
        of subject  : Any,          // parent (⭐ of type `Any`)
        type        : T.Type,       // child type
        recursive   : Bool = false, // first level only or all levels of children
        with handler: (T)->Void)    // child handler
    {
        // ⭐ mirror of `subject`
        let mirror = Mirror(reflecting: subject)

        // ⭐ do somethingfor each child.value of type `T`
        // ⭐ for case let ... where 
        //    ----------------------
        //    (pattern-match tuples + data binding + condition)
        //            ↱ ⭐ child.label ignored     ╭── ⭐ where ───╮
        for case let (_, value) in mirror.children where value is T {
            // handle T value
            handler(value as! T)     // ⭐ force type casting (Any -> T)
            // ⭐ handle children's T value recursively
            if recursive {
                handleChildren(of: value, type: T.self, recursive: true, with: handler)
            }
        }
    }
}
```
{% endtab %}

{% tab title="💈範例" %}
⬆️ 需要： [logger](../logger "mention")

```swift
// supporting types (Credentials, ...) not listed here.
struct Session {
    let credentials = Credentials()
    let favorites   = Favorites()
    let settings    = Settings()
}

extension Session {

    // 1. ⭐ reset everything one by one
    func logOut1() {
        Logger.box("# 1: manual reset")
        credentials.reset()
        favorites.reset()
        settings.reset()
    }

    // 2. ⭐ use `Mirror` to reset every `Resettable` (first level) child
    func logOut2() {

        Logger.box("# 2: use 'Mirror' directly")

        // 2.1: mirror self
        let mirror = Mirror(reflecting: self)

        // 2.2: inspect children
        // ⭐ `for case let ... where` (pattern matching + binding + condition)
        // ---------------------------------------------------------------------
        //            ↱ ⭐ child.label ignored     ╭─── ⭐ where clause ────╮
        for case let (_, value) in mirror.children where value is Resettable {

            // ⭐ 2.2.1: `if let ... as?` (optional binding)
            // ----------------------------------------------
            // if let resettable = child.value as? Resettable {
            //     resettable.reset()
            // }

            // ⭐ 2.2.2: `(... as? ...)?.method()` (optional chaining)
            // -------------------------------------------------------
            // for child in mirror.children {
            //     (child.value as? Resettable)?.reset()
            // }

            // ⭐ 2.2.3: `as!` force type casting (from Any to Resettable)
            // -----------------------------------------------------------
            // doing this is safe because `value` IS `Resettable`!
            (value as! Resettable).reset()
        }
    }

    // 3. ⭐ wrap "method 2" in `Mirror.handleChildren` meth
    func logOut3(){
        Logger.box("# 3: Mirror.handleChildren() (level 1)")
        // ⭐ use `handleChildren` on level 1 children
        Mirror.handleChildren(of: self, type: Resettable.self) { child in
            child.reset()
        }
    }

    // 4. ⭐ use `handleChildren` recursively
    func logOut4(){
        Logger.box("# 4: Mirror.handleChildren() (recursive)")
        Mirror.handleChildren(of: self, type: Resettable.self, recursive: true) { child in
            child.reset()
        }
        Logger.topline("⭐ this method has recursive mode.")
    }
}
```

#### 執行結果：

```swift
// ┌─────────────────────────┐
// │    # 1: manual reset    │
// └─────────────────────────┘
// 🔸 resetting `Credentials` ...
// 🔸 resetting `Favorites` ...
// 🔸 resetting `Settings` ...
// ┌──────────────────────────────────┐
// │    # 2: use 'Mirror' directly    │
// └──────────────────────────────────┘
// 🔸 resetting `Credentials` ...
// 🔸 resetting `Favorites` ...
// 🔸 resetting `Settings` ...
// ┌──────────────────────────────────────────────┐
// │    # 3: Mirror.handleChildren() (level 1)    │
// └──────────────────────────────────────────────┘
// 🔸 resetting `Credentials` ...
// 🔸 resetting `Favorites` ...
// 🔸 resetting `Settings` ...
// ┌────────────────────────────────────────────────┐
// │    # 4: Mirror.handleChildren() (recursive)    │
// └────────────────────────────────────────────────┘
// 🔸 resetting `Credentials` ...
// 🔸 resetting `Favorites` ...
// 🔸 resetting `Settings` ...
// 🔸 resetting `PreferredLanguages` ...
// ─────────────────────────────────
// ⭐ this method has recursive mode.\
```
{% endtab %}

{% tab title="📗 參考" %}
* [ ] Sundell ⟩ [Reflection in Swift](https://www.swiftbysundell.com/articles/reflection-in-swift/)
  * [x] [Recursive reflections](https://www.swiftbysundell.com/articles/reflection-in-swift/#recursive-reflections) ⭐️ (💈範例)
{% endtab %}

{% tab title="📘 手冊" %}
* [Swift](https://developer.apple.com/documentation/swift) ⟩&#x20;
  * [Debugging and Reflection](https://developer.apple.com/documentation/swift/swift_standard_library/debugging_and_reflection) ⟩ [Mirror](https://developer.apple.com/documentation/swift/mirror) (<mark style="color:red;">struct</mark>)
    * [Mirror.Child](https://developer.apple.com/documentation/swift/mirror/child)
    * [Mirror.Children](https://developer.apple.com/documentation/swift/mirror/children)
    * [Mirror.DisplayStyle](https://developer.apple.com/documentation/swift/mirror/displaystyle)
{% endtab %}

{% tab title="👥 相關" %}
* [pattern-matching](../../pattern-matching "mention") - pattern-match on [mirror]()'s <mark style="color:red;">**children**</mark>.
* [for-case-let-...-where](../../pattern-matching/sentence-patterns/for-case-let-...-where "mention") - (pattern matching + binding + condition)
* [if-let-...-as](../../pattern-matching/sentence-patterns/if-let-...-as "mention") - optional binding.
* [...-as-...-.method](../../pattern-matching/sentence-patterns/...-as-...-.method "mention") - optional chaining.
* [...-as-...](../../pattern-matching/sentence-patterns/...-as-... "mention") - force type casting.
* [logger](../logger "mention") is used in \[💈範例].
{% endtab %}
{% endtabs %}

## History

{% tabs %}
{% tab title="contents" %}
1. (2022.01.27) - first version. (global function)
{% endtab %}

{% tab title="1" %}
{% hint style="danger" %}
這個程式碼應該要寫成 global function，如果寫成 protocol method 會出現許多問題 (例如：children of children 可能根本不遵循這個 protocol，導致無法使用此 method recursively)

👉 💾 程式： [attemp 1 (with lots of errors)](https://replit.com/@pegasusroe/recursive-reflection-attempt-1)&#x20;
{% endhint %}



```swift
/// ⭐ handle children of type T
func handleChildren<T>(         // T: child's type ⭐ 
    of subject  : Any,          // parent (⭐ of type `Any`)
    type        : T.Type,       // child type
    recursive   : Bool = false, // first level only or all levels of children
    with handler: (T)->Void)    // child handler
{
    // ⭐ mirror of `subject`
    let mirror = Mirror(reflecting: subject)

    // ⭐ do somethingfor each child.value of type `T`
    // ⭐ for case let ... where 
    //    ----------------------
    //    (pattern-match tuples + data binding + condition)
    //            ↱ ⭐ child.label ignored     ╭── ⭐ where ───╮
    for case let (_, value) in mirror.children where value is T {
        // handle T value
        handler(value as! T)     // ⭐ force type casting (Any -> T)
        // ⭐ handle children's T value recursively
        if recursive {
            handleChildren(of: value, type: T.self, recursive: true, with: handler)
        }
    }
}
```
{% endtab %}
{% endtabs %}
