# 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](/ios/swift/debugging/logger.md)

```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](/ios/swift/pattern-matching.md) - pattern-match on [mirror](/ios/swift/debugging/mirror.md)'s <mark style="color:red;">**children**</mark>.
* [for case let ... where](/ios/swift/pattern-matching/sentence-patterns/for-case-let-...-where.md) - (pattern matching + binding + condition)
* [if let ... as?](/ios/swift/pattern-matching/sentence-patterns/if-let-...-as.md) - optional binding.
* [(... as? ...)?.method()](/ios/swift/pattern-matching/sentence-patterns/...-as-...-.method.md) - optional chaining.
* [... as! ...](/ios/swift/pattern-matching/sentence-patterns/...-as-....md) - force type casting.
* [Logger](/ios/swift/debugging/logger.md) 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/swift/debugging/mirror/mirror.handlechildren.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
