์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ” Swift ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ Mirror๋ฅผ ํ™œ์šฉํ•œ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ๊ฒ€์‚ฌ ์™„์ „ ์ •๋ณต

๐Ÿ” Swift ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ Mirror๋ฅผ ํ™œ์šฉํ•œ ๋Ÿฐํƒ€์ž„ ํƒ€์ž… ๊ฒ€์‚ฌ ์™„์ „ ์ •๋ณต

๋Ÿฐํƒ€์ž„์— ํƒ€์ž…์„ ๋“ค์—ฌ๋‹ค๋ณด๋Š” ๋งˆ๋ฒ• ๊ฐ™์€ ๊ธฐ์ˆ , ํ•จ๊ป˜ ํŒŒํ—ค์ณ๋ณผ๊นŒ์š”? ๐ŸŽฏ

์•ˆ๋…•! ์˜ค๋Š˜์€ Swift ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๊ผญ ์•Œ์•„์•ผ ํ•  ๋ฆฌํ”Œ๋ ‰์…˜(Reflection)๊ณผ Mirror์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณผ๊ฒŒ. ๐Ÿš€

์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค ๋ณด๋ฉด "์•„, ์ด ๋ณ€์ˆ˜๊ฐ€ ๋Ÿฐํƒ€์ž„์— ์–ด๋–ค ํƒ€์ž…์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ์€๋ฐ..." ํ•˜๋Š” ์ˆœ๊ฐ„์ด ์žˆ์ง€? ์ปดํŒŒ์ผ ํƒ€์ž„์—๋Š” ๋ชจ๋“  ๊ฒŒ ์ •ํ•ด์ ธ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ๋Œ์•„๊ฐˆ ๋•Œ๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ƒํ™ฉ๋“ค์ด ์ƒ๊ธฐ๊ฑฐ๋“ . ๋ฐ”๋กœ ์ด๋Ÿด ๋•Œ ๋ฆฌํ”Œ๋ ‰์…˜์ด ์ง„๊ฐ€๋ฅผ ๋ฐœํœ˜ํ•ด! ๐ŸŽญ

Swift Code Mirror Reflection Runtime Type Info ์ปดํŒŒ์ผ ํƒ€์ž„ ๋Ÿฐํƒ€์ž„ ๊ฒ€์‚ฌ ๋™์  ๋ถ„์„

๐ŸŽช ๋ฆฌํ”Œ๋ ‰์…˜์ด ๋ญ๊ธธ๋ž˜?

๋ฆฌํ”Œ๋ ‰์…˜์€ ํ”„๋กœ๊ทธ๋žจ์ด ์ž๊ธฐ ์ž์‹ ์˜ ๊ตฌ์กฐ๋ฅผ ๋“ค์—ฌ๋‹ค๋ณด๊ณ  ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์ด์•ผ. ๋งˆ์น˜ ๊ฑฐ์šธ(Mirror)์„ ๋ณด๋“ฏ์ด ์ž์‹ ์˜ ๋ชจ์Šต์„ ํ™•์ธํ•˜๋Š” ๊ฑฐ์ง€! ๐Ÿชž

์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ชจ๋“  ํƒ€์ž… ์ •๋ณด๋ฅผ ๋ฏธ๋ฆฌ ์•Œ๊ณ  ์žˆ์–ด. ํ•˜์ง€๋งŒ ๋•Œ๋กœ๋Š” ๋Ÿฐํƒ€์ž„์— "์ด ๊ฐ์ฒด๊ฐ€ ์–ด๋–ค ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€?", "์ด ๊ฐ’์˜ ์‹ค์ œ ํƒ€์ž…์ด ๋ญ์ง€?" ๊ฐ™์€ ์งˆ๋ฌธ์— ๋‹ตํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๊ฑฐ๋“ .

๐Ÿ’ก ๋ฆฌํ”Œ๋ ‰์…˜์ด ํ•„์š”ํ•œ ์‹ค์ œ ์ƒํ™ฉ๋“ค

โ€ข JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ
โ€ข ๋””๋ฒ„๊น… ๋„๊ตฌ๋‚˜ ๋กœ๊น… ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ๋•Œ
โ€ข ORM(Object-Relational Mapping) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌํ˜„
โ€ข ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๊ฐ์ฒด ์ƒํƒœ ๊ฒ€์ฆ
โ€ข ๋™์  UI ์ƒ์„ฑ์ด๋‚˜ ํผ ๋นŒ๋” ์ œ์ž‘
โ€ข ์‹œ๋ฆฌ์–ผ๋ผ์ด์ œ์ด์…˜/๋””์‹œ๋ฆฌ์–ผ๋ผ์ด์ œ์ด์…˜ ๊ตฌํ˜„

๐Ÿ”ฌ Swift์˜ Mirror: ํƒ€์ž…์„ ๋น„์ถ”๋Š” ๋งˆ๋ฒ•์˜ ๊ฑฐ์šธ

Swift์—์„œ๋Š” Mirror๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด. ์ด๋ฆ„๋ถ€ํ„ฐ ์ง๊ด€์ ์ด์ง€? ๊ฑฐ์šธ์ฒ˜๋Ÿผ ๊ฐ์ฒด์˜ ๋‚ด๋ถ€๋ฅผ ๋น„์ถฐ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค๋Š” ์˜๋ฏธ์•ผ! โœจ

๐Ÿ“Œ Mirror์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ

Mirror๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ์ •๋ณด๋“ค์„ ์ œ๊ณตํ•ด:

let mirror = Mirror(reflecting: someObject)

// ์ฃผ์š” ํ”„๋กœํผํ‹ฐ๋“ค
mirror.children        // ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋“ค
mirror.displayStyle    // ํ‘œ์‹œ ์Šคํƒ€์ผ (struct, class, enum ๋“ฑ)
mirror.subjectType     // ๋Œ€์ƒ์˜ ํƒ€์ž…
mirror.superclassMirror // ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ Mirror (์žˆ๋‹ค๋ฉด)

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋กœ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ? ๐ŸŽฏ

struct Person {
    let name: String
    let age: Int
    let email: String
}

let person = Person(name: "๊น€์ฒ ์ˆ˜", age: 28, email: "chulsoo@example.com")
let mirror = Mirror(reflecting: person)

print("ํƒ€์ž…: \(mirror.subjectType)")
print("ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜: \(mirror.children.count)")

for child in mirror.children {
    if let propertyName = child.label {
        print("\(propertyName): \(child.value)")
    }
}

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” ์ด๋ ‡๊ฒŒ ๋‚˜์™€:

ํƒ€์ž…: Person
ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜: 3
name: ๊น€์ฒ ์ˆ˜
age: 28
email: chulsoo@example.com

๋ณด๋‹ค์‹œํ”ผ Mirror๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ์ด๋ฆ„๊ณผ ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰

๐ŸŽฏ Mirror.Children: ํ”„๋กœํผํ‹ฐ ํƒํ—˜ํ•˜๊ธฐ

Mirror.children์€ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๋“ค์„ ๋‹ด๊ณ  ์žˆ๋Š” ์ปฌ๋ ‰์…˜์ด์•ผ. ๊ฐ child๋Š” (label: String?, value: Any) ํ˜•ํƒœ์˜ ํŠœํ”Œ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์ง€.

๐Ÿ” Children ๊นŠ์ด ํŒŒํ—ค์น˜๊ธฐ

struct Product {
    let id: Int
    let name: String
    let price: Double
    let inStock: Bool
    let tags: [String]
}

let product = Product(
    id: 101,
    name: "๋ฌด์„  ์ด์–ดํฐ",
    price: 89000,
    inStock: true,
    tags: ["์ „์ž์ œํ’ˆ", "์˜ค๋””์˜ค", "๋ธ”๋ฃจํˆฌ์Šค"]
)

let mirror = Mirror(reflecting: product)

// ๊ฐ ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…๊นŒ์ง€ ํ™•์ธํ•˜๊ธฐ
for child in mirror.children {
    let propertyName = child.label ?? "unknown"
    let propertyValue = child.value
    let propertyType = type(of: propertyValue)
    
    print("\(propertyName): \(propertyValue) (ํƒ€์ž…: \(propertyType))")
}

์ถœ๋ ฅ:

id: 101 (ํƒ€์ž…: Int)
name: ๋ฌด์„  ์ด์–ดํฐ (ํƒ€์ž…: String)
price: 89000.0 (ํƒ€์ž…: Double)
inStock: true (ํƒ€์ž…: Bool)
tags: ["์ „์ž์ œํ’ˆ", "์˜ค๋””์˜ค", "๋ธ”๋ฃจํˆฌ์Šค"] (ํƒ€์ž…: Array<String>)
๐Ÿ’ก Pro Tip
child.label์€ ์˜ต์…”๋„์ด์•ผ! ํŠœํ”Œ์ด๋‚˜ ๋ฐฐ์—ด ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” label์ด nil์ผ ์ˆ˜ ์žˆ์œผ๋‹ˆ ํ•ญ์ƒ ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•ด. ๐Ÿ˜Š

๐Ÿ—๏ธ DisplayStyle: ํƒ€์ž…์˜ ์ข…๋ฅ˜ ํŒŒ์•…ํ•˜๊ธฐ

Mirror๋Š” displayStyle์ด๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ๋Œ€์ƒ์ด ์–ด๋–ค ์ข…๋ฅ˜์˜ ํƒ€์ž…์ธ์ง€ ์•Œ๋ ค์ค˜. ์ด๊ฑด ์ •๋ง ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด์•ผ! ๐ŸŽจ

๐Ÿ“Š DisplayStyle์˜ ์ข…๋ฅ˜๋“ค

// DisplayStyle ์—ด๊ฑฐํ˜•์˜ ์ผ€์ด์Šค๋“ค
.struct      // ๊ตฌ์กฐ์ฒด
.class       // ํด๋ž˜์Šค
.enum        // ์—ด๊ฑฐํ˜•
.tuple       // ํŠœํ”Œ
.optional    // ์˜ต์…”๋„
.collection  // ์ปฌ๋ ‰์…˜ (Array, Set ๋“ฑ)
.dictionary  // ๋”•์…”๋„ˆ๋ฆฌ
.set         // Set

์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด์ž:

func analyzeType(_ value: Any) {
    let mirror = Mirror(reflecting: value)
    
    print("=== ํƒ€์ž… ๋ถ„์„ ===")
    print("ํƒ€์ž…: \(mirror.subjectType)")
    
    if let style = mirror.displayStyle {
        switch style {
        case .struct:
            print("์ด๊ฒƒ์€ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค! ๐Ÿ—๏ธ")
        case .class:
            print("์ด๊ฒƒ์€ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค! ๐ŸŽ“")
        case .enum:
            print("์ด๊ฒƒ์€ ์—ด๊ฑฐํ˜•์ž…๋‹ˆ๋‹ค! ๐Ÿ“‹")
        case .tuple:
            print("์ด๊ฒƒ์€ ํŠœํ”Œ์ž…๋‹ˆ๋‹ค! ๐Ÿ“ฆ")
        case .optional:
            print("์ด๊ฒƒ์€ ์˜ต์…”๋„์ž…๋‹ˆ๋‹ค! โ“")
        case .collection:
            print("์ด๊ฒƒ์€ ์ปฌ๋ ‰์…˜์ž…๋‹ˆ๋‹ค! ๐Ÿ“š")
        case .dictionary:
            print("์ด๊ฒƒ์€ ๋”•์…”๋„ˆ๋ฆฌ์ž…๋‹ˆ๋‹ค! ๐Ÿ“–")
        case .set:
            print("์ด๊ฒƒ์€ Set์ž…๋‹ˆ๋‹ค! ๐ŸŽฏ")
        @unknown default:
            print("์•Œ ์ˆ˜ ์—†๋Š” ํƒ€์ž…์ž…๋‹ˆ๋‹ค!")
        }
    }
    
    print("ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜: \(mirror.children.count)\n")
}

// ํ…Œ์ŠคํŠธ
struct Book { let title: String; let pages: Int }
class Author { let name: String; init(name: String) { self.name = name } }

analyzeType(Book(title: "Swift ๋งˆ์Šคํ„ฐ", pages: 500))
analyzeType(Author(name: "๊น€๊ฐœ๋ฐœ"))
analyzeType([1, 2, 3, 4, 5])
analyzeType(["name": "ํ™๊ธธ๋™", "age": "30"])

๐Ÿ”„ ์žฌ๊ท€์  Mirror: ์ค‘์ฒฉ๋œ ๊ตฌ์กฐ ํƒ์ƒ‰ํ•˜๊ธฐ

์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๊ฐ์ฒด ์•ˆ์— ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์žˆ๋Š” ์ค‘์ฒฉ ๊ตฌ์กฐ๊ฐ€ ํ”ํ•˜์ง€? Mirror๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฐ ๋ณต์žกํ•œ ๊ตฌ์กฐ๋„ ์™„๋ฒฝํ•˜๊ฒŒ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŒณ

๐ŸŽ„ ์ค‘์ฒฉ ๊ตฌ์กฐ ์™„์ „ ์ •๋ณต

struct Address {
    let street: String
    let city: String
    let zipCode: String
}

struct Company {
    let name: String
    let address: Address
}

struct Employee {
    let name: String
    let age: Int
    let company: Company
}

func printObjectStructure(_ object: Any, indent: String = "") {
    let mirror = Mirror(reflecting: object)
    
    for child in mirror.children {
        let label = child.label ?? "unnamed"
        let value = child.value
        
        print("\(indent)โ”œโ”€ \(label): ", terminator: "")
        
        let childMirror = Mirror(reflecting: value)
        
        // ์ž์‹์ด ์žˆ์œผ๋ฉด ์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰
        if childMirror.children.count > 0 {
            print("\(type(of: value))")
            printObjectStructure(value, indent: indent + "โ”‚  ")
        } else {
            print("\(value)")
        }
    }
}

let employee = Employee(
    name: "์ด์˜ํฌ",
    age: 32,
    company: Company(
        name: "ํ…Œํฌ์Šคํƒ€ํŠธ์—…",
        address: Address(
            street: "ํ…Œํ—ค๋ž€๋กœ 123",
            city: "์„œ์šธ",
            zipCode: "06234"
        )
    )
)

print("๐ŸŒณ ๊ฐ์ฒด ๊ตฌ์กฐ ํŠธ๋ฆฌ:")
printObjectStructure(employee)

์ถœ๋ ฅ ๊ฒฐ๊ณผ:

๐ŸŒณ ๊ฐ์ฒด ๊ตฌ์กฐ ํŠธ๋ฆฌ:
โ”œโ”€ name: ์ด์˜ํฌ
โ”œโ”€ age: 32
โ”œโ”€ company: Company
โ”‚  โ”œโ”€ name: ํ…Œํฌ์Šคํƒ€ํŠธ์—…
โ”‚  โ”œโ”€ address: Address
โ”‚  โ”‚  โ”œโ”€ street: ํ…Œํ—ค๋ž€๋กœ 123
โ”‚  โ”‚  โ”œโ”€ city: ์„œ์šธ
โ”‚  โ”‚  โ”œโ”€ zipCode: 06234

์™€! ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๊น”๋”ํ•˜๊ฒŒ ์ถœ๋ ฅ๋˜์ง€? ์ด๋Ÿฐ ์‹์œผ๋กœ ์•„๋ฌด๋ฆฌ ๋ณต์žกํ•œ ๊ฐ์ฒด ๊ตฌ์กฐ๋„ ์™„๋ฒฝํ•˜๊ฒŒ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰

๐ŸŽญ ํƒ€์ž… ์บ์ŠคํŒ…๊ณผ Mirror์˜ ์กฐํ•ฉ

Mirror์™€ ํƒ€์ž… ์บ์ŠคํŒ…์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ํ”„๋กœํ† ์ฝœ ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋น›์„ ๋ฐœํ•˜์ง€! โœจ

๐ŸŽช ํ”„๋กœํ† ์ฝœ๊ณผ Mirror์˜ ํ™˜์ƒ ์กฐํ•ฉ

protocol Describable {
    var description: String { get }
}

struct User: Describable {
    let id: Int
    let username: String
    let email: String
    
    var description: String {
        return "User #\(id): \(username)"
    }
}

struct Post: Describable {
    let title: String
    let content: String
    let author: String
    
    var description: String {
        return "'\(title)' by \(author)"
    }
}

func analyzeDescribable(_ items: [Any]) {
    for item in items {
        let mirror = Mirror(reflecting: item)
        
        print("\n๐Ÿ“ฆ ํƒ€์ž…: \(mirror.subjectType)")
        
        // Describable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ–ˆ๋Š”์ง€ ํ™•์ธ
        if let describable = item as? Describable {
            print("โœ… Describable ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ")
            print("๐Ÿ“ ์„ค๋ช…: \(describable.description)")
        } else {
            print("โŒ Describable ํ”„๋กœํ† ์ฝœ ๋ฏธ์ฑ„ํƒ")
        }
        
        // ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ ์ถœ๋ ฅ
        print("๐Ÿ” ํ”„๋กœํผํ‹ฐ:")
        for child in mirror.children {
            if let label = child.label {
                print("   โ€ข \(label): \(child.value)")
            }
        }
    }
}

let user = User(id: 1, username: "swiftmaster", email: "swift@example.com")
let post = Post(title: "Mirror ์™„์ „์ •๋ณต", content: "...", author: "๊น€๊ฐœ๋ฐœ")
let number = 42

analyzeDescribable([user, post, number])
โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ
Mirror๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด์•ผ! ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์ˆ˜์ •ํ•  ์ˆ˜๋Š” ์—†์–ด. ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด. ๐Ÿ”’

๐Ÿ› ๏ธ ์‹ค์ „ ํ™œ์šฉ: JSON ์ง๋ ฌํ™” ๊ตฌํ˜„ํ•˜๊ธฐ

์ด์ œ ๋ฐฐ์šด ๋‚ด์šฉ์„ ํ™œ์šฉํ•ด์„œ ์‹ค์ œ๋กœ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋ณผ๊นŒ? ๊ฐ„๋‹จํ•œ JSON ์ง๋ ฌํ™” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž! ์ด๊ฑด ์ •๋ง ์‹ค๋ฌด์—์„œ๋„ ์ž์ฃผ ์“ฐ์ด๋Š” ํŒจํ„ด์ด์•ผ. ๐Ÿš€

๐Ÿ’Ž ์ปค์Šคํ…€ JSON ์ธ์ฝ”๋” ๋งŒ๋“ค๊ธฐ

func toJSON(_ object: Any) -> String {
    let mirror = Mirror(reflecting: object)
    
    guard mirror.children.count > 0 else {
        // ๊ธฐ๋ณธ ํƒ€์ž… ์ฒ˜๋ฆฌ
        if let string = object as? String {
            return "\"\(string)\""
        } else if let number = object as? CustomStringConvertible {
            return "\(number)"
        }
        return "\"\(object)\""
    }
    
    var json = "{"
    var isFirst = true
    
    for child in mirror.children {
        guard let label = child.label else { continue }
        
        if !isFirst {
            json += ","
        }
        isFirst = false
        
        json += "\"\(label)\":"
        
        let value = child.value
        let valueMirror = Mirror(reflecting: value)
        
        // ์ค‘์ฒฉ ๊ฐ์ฒด ์ฒ˜๋ฆฌ
        if valueMirror.children.count > 0 {
            json += toJSON(value)
        } else if let string = value as? String {
            json += "\"\(string)\""
        } else if let array = value as? [Any] {
            json += "["
            json += array.map { toJSON($0) }.joined(separator: ",")
            json += "]"
        } else {
            json += "\(value)"
        }
    }
    
    json += "}"
    return json
}

// ํ…Œ์ŠคํŠธ
struct BlogPost {
    let id: Int
    let title: String
    let author: String
    let tags: [String]
    let published: Bool
}

let post = BlogPost(
    id: 42,
    title: "Swift Mirror ๋งˆ์Šคํ„ฐํ•˜๊ธฐ",
    author: "๊น€๊ฐœ๋ฐœ",
    tags: ["Swift", "iOS", "Programming"],
    published: true
)

let jsonString = toJSON(post)
print("๐Ÿ“„ ์ƒ์„ฑ๋œ JSON:")
print(jsonString)

์ถœ๋ ฅ:

๐Ÿ“„ ์ƒ์„ฑ๋œ JSON:
{"id":42,"title":"Swift Mirror ๋งˆ์Šคํ„ฐํ•˜๊ธฐ","author":"๊น€๊ฐœ๋ฐœ","tags":["Swift","iOS","Programming"],"published":true}

์™„๋ฒฝํ•˜์ง€? ๋ฌผ๋ก  ์‹ค์ œ ํ”„๋กœ๋•์…˜์—์„œ๋Š” Codable ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋” ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์ด์ง€๋งŒ, Mirror์˜ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ๋Š” ์ด๋Ÿฐ ์˜ˆ์ œ๊ฐ€ ์ตœ๊ณ ์•ผ! ๐Ÿ’ช

๐Ÿ” ํƒ€์ž… ์•ˆ์ „์„ฑ๊ณผ Mirror

Swift๋Š” ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ์ค‘์š”ํ•˜๊ฒŒ ์—ฌ๊ธฐ๋Š” ์–ธ์–ด์•ผ. ๊ทธ๋Ÿฐ๋ฐ Mirror๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Any ํƒ€์ž…์„ ๋‹ค๋ฃจ๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์–ด. ๐Ÿ›ก๏ธ

๐ŸŽฏ ์•ˆ์ „ํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ ํŒจํ„ด

func safelyExtractValue<T>(from object: Any, key: String, as type: T.Type) -> T? {
    let mirror = Mirror(reflecting: object)
    
    for child in mirror.children {
        if child.label == key {
            return child.value as? T
        }
    }
    
    return nil
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
struct Config {
    let apiKey: String
    let timeout: Int
    let enableLogging: Bool
}

let config = Config(
    apiKey: "abc123xyz",
    timeout: 30,
    enableLogging: true
)

// ์•ˆ์ „ํ•œ ๊ฐ’ ์ถ”์ถœ
if let apiKey = safelyExtractValue(from: config, key: "apiKey", as: String.self) {
    print("โœ… API Key: \(apiKey)")
}

if let timeout = safelyExtractValue(from: config, key: "timeout", as: Int.self) {
    print("โœ… Timeout: \(timeout)์ดˆ")
}

// ์ž˜๋ชป๋œ ํƒ€์ž…์œผ๋กœ ์‹œ๋„ํ•˜๋ฉด nil ๋ฐ˜ํ™˜
if let wrongType = safelyExtractValue(from: config, key: "timeout", as: String.self) {
    print("์ด ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ")
} else {
    print("โŒ ํƒ€์ž… ๋ถˆ์ผ์น˜: timeout์€ String์ด ์•„๋‹™๋‹ˆ๋‹ค")
}

๐ŸŽจ ๊ณ ๊ธ‰ ํ™œ์šฉ: ๊ฐ์ฒด ๋น„๊ต ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ

Mirror๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ตํ•˜๋Š” ๋ฒ”์šฉ ํ•จ์ˆ˜๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ด๊ฑด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•  ๋•Œ ํŠนํžˆ ์œ ์šฉํ•˜์ง€! ๐Ÿงช

โš–๏ธ ๋ฒ”์šฉ ๊ฐ์ฒด ๋น„๊ต๊ธฐ

func areEqual(_ lhs: Any, _ rhs: Any) -> Bool {
    let lhsMirror = Mirror(reflecting: lhs)
    let rhsMirror = Mirror(reflecting: rhs)
    
    // ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฉด false
    if lhsMirror.subjectType != rhsMirror.subjectType {
        return false
    }
    
    // ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋ฉด false
    if lhsMirror.children.count != rhsMirror.children.count {
        return false
    }
    
    // ๊ฐ ํ”„๋กœํผํ‹ฐ ๋น„๊ต
    let lhsChildren = Array(lhsMirror.children)
    let rhsChildren = Array(rhsMirror.children)
    
    for (index, lhsChild) in lhsChildren.enumerated() {
        let rhsChild = rhsChildren[index]
        
        // ๋ ˆ์ด๋ธ” ๋น„๊ต
        if lhsChild.label != rhsChild.label {
            return false
        }
        
        // ๊ฐ’ ๋น„๊ต (์žฌ๊ท€์ ์œผ๋กœ)
        let lhsValue = lhsChild.value
        let rhsValue = rhsChild.value
        
        // ๊ธฐ๋ณธ ํƒ€์ž…๋“ค์€ ์ง์ ‘ ๋น„๊ต
        if let lhsString = lhsValue as? String,
           let rhsString = rhsValue as? String {
            if lhsString != rhsString { return false }
        } else if let lhsInt = lhsValue as? Int,
                  let rhsInt = rhsValue as? Int {
            if lhsInt != rhsInt { return false }
        } else if let lhsBool = lhsValue as? Bool,
                  let rhsBool = rhsValue as? Bool {
            if lhsBool != rhsBool { return false }
        } else {
            // ๋ณต์žกํ•œ ํƒ€์ž…์€ ์žฌ๊ท€์ ์œผ๋กœ ๋น„๊ต
            if !areEqual(lhsValue, rhsValue) {
                return false
            }
        }
    }
    
    return true
}

// ํ…Œ์ŠคํŠธ
struct Point {
    let x: Int
    let y: Int
}

let point1 = Point(x: 10, y: 20)
let point2 = Point(x: 10, y: 20)
let point3 = Point(x: 15, y: 25)

print("point1 == point2: \(areEqual(point1, point2))") // true
print("point1 == point3: \(areEqual(point1, point3))") // false

๐ŸŒŸ SuperclassMirror: ์ƒ์† ๊ตฌ์กฐ ํƒ์ƒ‰ํ•˜๊ธฐ

ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ์ƒ์† ๊ด€๊ณ„๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์ง€? Mirror๋Š” superclassMirror ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ •๋ณด๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜! ๐Ÿฐ

๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ์ƒ์† ์ฒด์ธ ๋”ฐ๋ผ๊ฐ€๊ธฐ

class Animal {
    let species: String
    let age: Int
    
    init(species: String, age: Int) {
        self.species = species
        self.age = age
    }
}

class Dog: Animal {
    let name: String
    let breed: String
    
    init(name: String, breed: String, age: Int) {
        self.name = name
        self.breed = breed
        super.init(species: "Canis familiaris", age: age)
    }
}

class Puppy: Dog {
    let isVaccinated: Bool
    
    init(name: String, breed: String, age: Int, isVaccinated: Bool) {
        self.isVaccinated = isVaccinated
        super.init(name: name, breed: breed, age: age)
    }
}

func printInheritanceChain(_ object: Any) {
    var currentMirror: Mirror? = Mirror(reflecting: object)
    var level = 0
    
    while let mirror = currentMirror {
        let indent = String(repeating: "  ", count: level)
        print("\(indent)๐Ÿ“ฆ \(mirror.subjectType)")
        
        for child in mirror.children {
            if let label = child.label {
                print("\(indent)  โ”œโ”€ \(label): \(child.value)")
            }
        }
        
        currentMirror = mirror.superclassMirror
        level += 1
        
        if currentMirror != nil {
            print("\(indent)  โฌ†๏ธ  ์ƒ์†")
        }
    }
}

let puppy = Puppy(
    name: "์ดˆ์ฝ”",
    breed: "๊ณจ๋“  ๋ฆฌํŠธ๋ฆฌ๋ฒ„",
    age: 1,
    isVaccinated: true
)

print("๐Ÿ• ์ƒ์† ๊ตฌ์กฐ ๋ถ„์„:")
printInheritanceChain(puppy)

์ถœ๋ ฅ:

๐Ÿ• ์ƒ์† ๊ตฌ์กฐ ๋ถ„์„:
๐Ÿ“ฆ Puppy
  โ”œโ”€ isVaccinated: true
  โฌ†๏ธ  ์ƒ์†
  ๐Ÿ“ฆ Dog
    โ”œโ”€ name: ์ดˆ์ฝ”
    โ”œโ”€ breed: ๊ณจ๋“  ๋ฆฌํŠธ๋ฆฌ๋ฒ„
    โฌ†๏ธ  ์ƒ์†
    ๐Ÿ“ฆ Animal
      โ”œโ”€ species: Canis familiaris
      โ”œโ”€ age: 1

์™„๋ฒฝํ•˜๊ฒŒ ์ƒ์† ์ฒด์ธ์„ ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด! ์ด๋Ÿฐ ๊ธฐ๋Šฅ์€ ๋””๋ฒ„๊น…์ด๋‚˜ ๋กœ๊น… ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ๋•Œ ์ •๋ง ์œ ์šฉํ•ด. ๐ŸŽฏ

๐ŸŽช ์—ด๊ฑฐํ˜•(Enum)๊ณผ Mirror

์—ด๊ฑฐํ˜•์€ Swift์—์„œ ์ •๋ง ๊ฐ•๋ ฅํ•œ ํƒ€์ž…์ด์ง€? Mirror๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ด๊ฑฐํ˜•์˜ associated value๋„ ์‰ฝ๊ฒŒ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽญ

๐ŸŽฒ Associated Value ์ถ”์ถœํ•˜๊ธฐ

enum NetworkResponse {
    case success(data: Data, statusCode: Int)
    case failure(error: Error, statusCode: Int)
    case loading
    case idle
}

struct MockError: Error {
    let message: String
}

func analyzeResponse(_ response: NetworkResponse) {
    let mirror = Mirror(reflecting: response)
    
    print("๐Ÿ” ์‘๋‹ต ๋ถ„์„")
    print("ํƒ€์ž…: \(mirror.subjectType)")
    print("DisplayStyle: \(mirror.displayStyle ?? .enum)")
    
    // ์—ด๊ฑฐํ˜• ์ผ€์ด์Šค ์ด๋ฆ„ ์ถ”์ถœ
    if let firstChild = mirror.children.first {
        print("์ผ€์ด์Šค: \(firstChild.label ?? "unknown")")
        
        // Associated values ์ถ”์ถœ
        let associatedMirror = Mirror(reflecting: firstChild.value)
        if associatedMirror.children.count > 0 {
            print("Associated Values:")
            for (index, child) in associatedMirror.children.enumerated() {
                let label = child.label ?? "value\(index)"
                print("  โ€ข \(label): \(child.value)")
            }
        } else {
            print("Associated Values ์—†์Œ")
        }
    }
    print()
}

// ํ…Œ์ŠคํŠธ
let successResponse = NetworkResponse.success(
    data: Data(),
    statusCode: 200
)

let failureResponse = NetworkResponse.failure(
    error: MockError(message: "๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜"),
    statusCode: 500
)

let loadingResponse = NetworkResponse.loading

analyzeResponse(successResponse)
analyzeResponse(failureResponse)
analyzeResponse(loadingResponse)

์ถœ๋ ฅ:

๐Ÿ” ์‘๋‹ต ๋ถ„์„
ํƒ€์ž…: NetworkResponse
DisplayStyle: enum
์ผ€์ด์Šค: success
Associated Values:
  โ€ข data: 0 bytes
  โ€ข statusCode: 200

๐Ÿ” ์‘๋‹ต ๋ถ„์„
ํƒ€์ž…: NetworkResponse
DisplayStyle: enum
์ผ€์ด์Šค: failure
Associated Values:
  โ€ข error: MockError(message: "๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜")
  โ€ข statusCode: 500

๐Ÿ” ์‘๋‹ต ๋ถ„์„
ํƒ€์ž…: NetworkResponse
DisplayStyle: enum
์ผ€์ด์Šค: loading
Associated Values ์—†์Œ

๐Ÿš€ ์„ฑ๋Šฅ ๊ณ ๋ ค์‚ฌํ•ญ

Mirror๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์–ด. ๋ฆฌํ”Œ๋ ‰์…˜์€ ๋ณธ์งˆ์ ์œผ๋กœ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ๊ฑฐ๋“ ! โšก

โš ๏ธ ์„ฑ๋Šฅ ์ฃผ์˜์‚ฌํ•ญ

1. ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ
Mirror๋ฅผ ์‚ฌ์šฉํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„ ํƒ€์ž… ๊ฒ€์‚ฌ๋ณด๋‹ค ๋А๋ ค. ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๋ฃจํ”„ ์•ˆ์—์„œ๋Š” ์‚ฌ์šฉ์„ ์ž์ œํ•˜์ž.

2. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ
Mirror ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ• ๋‹น๋ผ. ๋Œ€๋Ÿ‰์˜ ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ด.

3. ์ตœ์ ํ™” ์ œํ•œ
์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ฆฌํ”Œ๋ ‰์…˜ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๊ธฐ ์–ด๋ ค์›Œ. ๊ฐ€๋Šฅํ•˜๋ฉด ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ์„ ํ™œ์šฉํ•˜์ž.

4. ๋Œ€์•ˆ ๊ณ ๋ ค
โ€ข Codable: JSON ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™”
โ€ข ํ”„๋กœํ† ์ฝœ: ํƒ€์ž…๋ณ„ ๋™์ž‘ ์ •์˜
โ€ข ์ œ๋„ค๋ฆญ: ํƒ€์ž… ์•ˆ์ „ํ•œ ๋ฒ”์šฉ ์ฝ”๋“œ

๐Ÿ“Š ์„ฑ๋Šฅ ๋น„๊ต ์˜ˆ์ œ

import Foundation

struct TestData {
    let id: Int
    let name: String
    let value: Double
}

// Mirror ์‚ฌ์šฉ
func extractWithMirror(_ data: TestData) -> String {
    let mirror = Mirror(reflecting: data)
    var result = ""
    for child in mirror.children {
        if let label = child.label {
            result += "\(label): \(child.value), "
        }
    }
    return result
}

// ์ง์ ‘ ์ ‘๊ทผ
func extractDirect(_ data: TestData) -> String {
    return "id: \(data.id), name: \(data.name), value: \(data.value)"
}

let testData = TestData(id: 1, name: "ํ…Œ์ŠคํŠธ", value: 3.14)

// ์„ฑ๋Šฅ ์ธก์ •
let iterations = 100_000

let mirrorStart = Date()
for _ in 0..<iterations {
    _ = extractWithMirror(testData)
}
let mirrorTime = Date().timeIntervalSince(mirrorStart)

let directStart = Date()
for _ in 0..<iterations {
    _ = extractDirect(testData)
}
let directTime = Date().timeIntervalSince(directStart)

print("๐Ÿ“Š ์„ฑ๋Šฅ ๋น„๊ต (\(iterations)ํšŒ ๋ฐ˜๋ณต)")
print("Mirror ์‚ฌ์šฉ: \(String(format: "%.4f", mirrorTime))์ดˆ")
print("์ง์ ‘ ์ ‘๊ทผ: \(String(format: "%.4f", directTime))์ดˆ")
print("์ฐจ์ด: \(String(format: "%.1f", mirrorTime / directTime))๋ฐฐ")

์ผ๋ฐ˜์ ์œผ๋กœ Mirror๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฉ์‹์ด ์ง์ ‘ ์ ‘๊ทผ๋ณด๋‹ค 10~20๋ฐฐ ์ •๋„ ๋А๋ ค. ํ•˜์ง€๋งŒ ์ด๊ฑด ๊ทน๋‹จ์ ์ธ ๋ฐ˜๋ณต ์ƒํ™ฉ์ด๊ณ , ์‹ค์ œ ์•ฑ์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ์•ˆ ๋ผ. ์ ์žฌ์ ์†Œ์— ์‚ฌ์šฉํ•˜๋ฉด ๋ผ! ๐Ÿ˜Š

๐ŸŽฏ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ๋””๋ฒ„๊น… ๋„๊ตฌ ๋งŒ๋“ค๊ธฐ

์ด์ œ ๋ฐฐ์šด ๋ชจ๋“  ๋‚ด์šฉ์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์šฉ์ ์ธ ๋””๋ฒ„๊น… ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ์ด๊ฑด ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์ด์•ผ. ๐Ÿ› ๏ธ

๐Ÿ”ง ์™„์ „ํ•œ ๊ฐ์ฒด ๋คํ”„ ์œ ํ‹ธ๋ฆฌํ‹ฐ

class ObjectDumper {
    
    enum DumpStyle {
        case compact
        case detailed
        case json
    }
    
    static func dump(_ object: Any, style: DumpStyle = .detailed) -> String {
        switch style {
        case .compact:
            return dumpCompact(object)
        case .detailed:
            return dumpDetailed(object)
        case .json:
            return dumpJSON(object)
        }
    }
    
    // ๊ฐ„๋‹จํ•œ ํ˜•์‹
    private static func dumpCompact(_ object: Any) -> String {
        let mirror = Mirror(reflecting: object)
        var result = "\(mirror.subjectType)("
        
        let properties = mirror.children.compactMap { child -> String? in
            guard let label = child.label else { return nil }
            return "\(label): \(child.value)"
        }
        
        result += properties.joined(separator: ", ")
        result += ")"
        return result
    }
    
    // ์ƒ์„ธํ•œ ํ˜•์‹
    private static func dumpDetailed(_ object: Any, indent: Int = 0) -> String {
        let mirror = Mirror(reflecting: object)
        let indentStr = String(repeating: "  ", count: indent)
        var result = ""
        
        if indent == 0 {
            result += "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—\n"
            result += "โ•‘  Object Dump - Detailed View         โ•‘\n"
            result += "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n\n"
        }
        
        result += "\(indentStr)๐Ÿ“ฆ Type: \(mirror.subjectType)\n"
        
        if let displayStyle = mirror.displayStyle {
            result += "\(indentStr)๐Ÿท๏ธ  Style: \(displayStyle)\n"
        }
        
        if mirror.children.count > 0 {
            result += "\(indentStr)๐Ÿ“‹ Properties (\(mirror.children.count)):\n"
            
            for child in mirror.children {
                let label = child.label ?? "unnamed"
                let value = child.value
                let valueMirror = Mirror(reflecting: value)
                
                result += "\(indentStr)  โ€ข \(label): "
                
                if valueMirror.children.count > 0 {
                    result += "\n"
                    result += dumpDetailed(value, indent: indent + 2)
                } else {
                    result += "\(value) (\(type(of: value)))\n"
                }
            }
        }
        
        // ์ƒ์† ์ •๋ณด
        if let superMirror = mirror.superclassMirror {
            result += "\(indentStr)โฌ†๏ธ  Inherits from:\n"
            result += dumpDetailed(superMirror, indent: indent + 1)
        }
        
        return result
    }
    
    // JSON ํ˜•์‹
    private static func dumpJSON(_ object: Any, indent: Int = 0) -> String {
        let mirror = Mirror(reflecting: object)
        let indentStr = String(repeating: "  ", count: indent)
        
        guard mirror.children.count > 0 else {
            if let string = object as? String {
                return "\"\(string)\""
            }
            return "\(object)"
        }
        
        var json = "{\n"
        let properties = Array(mirror.children)
        
        for (index, child) in properties.enumerated() {
            guard let label = child.label else { continue }
            
            json += "\(indentStr)  \"\(label)\": "
            
            let value = child.value
            let valueMirror = Mirror(reflecting: value)
            
            if valueMirror.children.count > 0 {
                json += dumpJSON(value, indent: indent + 1)
            } else if let string = value as? String {
                json += "\"\(string)\""
            } else if let array = value as? [Any] {
                json += "[\n"
                for (i, item) in array.enumerated() {
                    json += "\(indentStr)    \(dumpJSON(item, indent: indent + 2))"
                    if i < array.count - 1 { json += "," }
                    json += "\n"
                }
                json += "\(indentStr)  ]"
            } else {
                json += "\(value)"
            }
            
            if index < properties.count - 1 {
                json += ","
            }
            json += "\n"
        }
        
        json += "\(indentStr)}"
        return json
    }
}

// ํ…Œ์ŠคํŠธ์šฉ ๋ณต์žกํ•œ ๊ตฌ์กฐ
struct Project {
    let name: String
    let version: String
    let contributors: [String]
    let settings: Settings
}

struct Settings {
    let debugMode: Bool
    let maxConnections: Int
    let apiEndpoint: String
}

let project = Project(
    name: "SwiftMirrorDemo",
    version: "1.0.0",
    contributors: ["๊น€๊ฐœ๋ฐœ", "์ด์ฝ”๋”ฉ", "๋ฐ•ํ”„๋กœ๊ทธ๋ž˜๋จธ"],
    settings: Settings(
        debugMode: true,
        maxConnections: 100,
        apiEndpoint: "https://api.example.com"
    )
)

print("=== COMPACT ===")
print(ObjectDumper.dump(project, style: .compact))
print("\n=== DETAILED ===")
print(ObjectDumper.dump(project, style: .detailed))
print("\n=== JSON ===")
print(ObjectDumper.dump(project, style: .json))

์ด ๋„๊ตฌ๋Š” ์‹ค์ œ๋กœ ๋””๋ฒ„๊น…ํ•  ๋•Œ ์—„์ฒญ ์œ ์šฉํ•ด! ๋ณต์žกํ•œ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ ํ•œ๋ˆˆ์— ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๐ŸŽ‰

๐ŸŒˆ Mirror์˜ ํ•œ๊ณ„์™€ ๋Œ€์•ˆ

Mirror๋Š” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ์™„๋ฒฝํ•˜์ง€๋Š” ์•Š์•„. ๋ช‡ ๊ฐ€์ง€ ํ•œ๊ณ„์ ์ด ์žˆ๊ณ , ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋” ๋‚˜์€ ๋Œ€์•ˆ์ด ์žˆ์„ ์ˆ˜ ์žˆ์–ด. ๐Ÿค”

๐Ÿšง Mirror์˜ ํ•œ๊ณ„์ 

1. ์ฝ๊ธฐ ์ „์šฉ
Mirror๋กœ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฝ์„ ์ˆ˜๋งŒ ์žˆ๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์–ด. ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด KeyPath๋‚˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด.

2. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ œํ•œ
ํ”„๋กœํผํ‹ฐ์˜ ์ ‘๊ทผ ์ œ์–ด์ž(private, public ๋“ฑ)๋‚˜ ์†์„ฑ(lazy, computed ๋“ฑ)์€ ์•Œ ์ˆ˜ ์—†์–ด.

3. ๋ฉ”์„œ๋“œ ์ •๋ณด ์—†์Œ
Mirror๋Š” ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋งŒ ๋ณด์—ฌ์ค˜. ๋ฉ”์„œ๋“œ๋‚˜ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†์–ด.

4. ํƒ€์ž… ์ •๋ณด ์ œํ•œ
์ œ๋„ค๋ฆญ ํƒ€์ž…์˜ ๊ตฌ์ฒด์ ์ธ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์™„์ „ํžˆ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์›Œ.

โœจ ์ƒํ™ฉ๋ณ„ ๋Œ€์•ˆ

// 1. ๊ฐ’ ์ˆ˜์ •์ด ํ•„์š”ํ•  ๋•Œ: KeyPath ์‚ฌ์šฉ
struct User {
    var name: String
    var age: Int
}

var user = User(name: "ํ™๊ธธ๋™", age: 30)
let nameKeyPath = \User.name

// KeyPath๋กœ ๊ฐ’ ์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ
print(user[keyPath: nameKeyPath])  // "ํ™๊ธธ๋™"
user[keyPath: nameKeyPath] = "๊น€์ฒ ์ˆ˜"
print(user[keyPath: nameKeyPath])  // "๊น€์ฒ ์ˆ˜"

// 2. ์ง๋ ฌํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ: Codable ์‚ฌ์šฉ
struct Product: Codable {
    let id: Int
    let name: String
    let price: Double
}

let product = Product(id: 1, name: "๋…ธํŠธ๋ถ", price: 1500000)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

if let jsonData = try? encoder.encode(product),
   let jsonString = String(data: jsonData, encoding: .utf8) {
    print(jsonString)
}

// 3. ํƒ€์ž…๋ณ„ ๋™์ž‘์ด ํ•„์š”ํ•  ๋•Œ: ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ
protocol Printable {
    func prettyPrint() -> String
}

extension User: Printable {
    func prettyPrint() -> String {
        return "๐Ÿ‘ค \(name) (๋‚˜์ด: \(age))"
    }
}

extension Product: Printable {
    func prettyPrint() -> String {
        return "๐Ÿ›๏ธ \(name) - โ‚ฉ\(price)"
    }
}

// 4. ๋ฒ”์šฉ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ: ์ œ๋„ค๋ฆญ ์‚ฌ์šฉ
func process<T>(_ items: [T], transform: (T) -> String) {
    for item in items {
        print(transform(item))
    }
}

๐Ÿ’ผ ์‹ค๋ฌด ํ™œ์šฉ ์‚ฌ๋ก€

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ Mirror๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž! ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ. ๐ŸŽจ

๐ŸŽฏ ์‚ฌ๋ก€ 1: ํผ ๊ฒ€์ฆ ์‹œ์Šคํ…œ

protocol Validatable {
    func validate() -> [String]  // ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฐฐ์—ด
}

struct ValidationRule {
    let fieldName: String
    let validator: (Any) -> String?
}

class FormValidator {
    
    static func validate(_ object: Any, rules: [ValidationRule]) -> [String: String] {
        let mirror = Mirror(reflecting: object)
        var errors: [String: String] = [:]
        
        for rule in rules {
            // ํ•ด๋‹น ํ•„๋“œ ์ฐพ๊ธฐ
            for child in mirror.children {
                if child.label == rule.fieldName {
                    if let error = rule.validator(child.value) {
                        errors[rule.fieldName] = error
                    }
                    break
                }
            }
        }
        
        return errors
    }
    
    // ์ผ๋ฐ˜์ ์ธ ๊ฒ€์ฆ ๊ทœ์น™๋“ค
    static func required(_ value: Any) -> String? {
        if let string = value as? String, string.isEmpty {
            return "ํ•„์ˆ˜ ์ž…๋ ฅ ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค"
        }
        return nil
    }
    
    static func minLength(_ min: Int) -> (Any) -> String? {
        return { value in
            if let string = value as? String, string.count < min {
                return "์ตœ์†Œ \(min)์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”"
            }
            return nil
        }
    }
    
    static func email(_ value: Any) -> String? {
        guard let string = value as? String else { return nil }
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let predicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        if !predicate.evaluate(with: string) {
            return "์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค"
        }
        return nil
    }
}

// ์žฌ๋Šฅ๋„ท ํšŒ์›๊ฐ€์ž… ํผ
struct SignupForm {
    let username: String
    let email: String
    let password: String
    let bio: String
}

let form = SignupForm(
    username: "๊ฐœ๋ฐœ์ž",
    email: "invalid-email",
    password: "123",
    bio: "์•ˆ๋…•ํ•˜์„ธ์š”"
)

let rules = [
    ValidationRule(fieldName: "username", validator: FormValidator.required),
    ValidationRule(fieldName: "username", validator: FormValidator.minLength(2)),
    ValidationRule(fieldName: "email", validator: FormValidator.email),
    ValidationRule(fieldName: "password", validator: FormValidator.minLength(8))
]

let errors = FormValidator.validate(form, rules: rules)

if errors.isEmpty {
    print("โœ… ๊ฒ€์ฆ ํ†ต๊ณผ!")
} else {
    print("โŒ ๊ฒ€์ฆ ์‹คํŒจ:")
    for (field, error) in errors {
        print("  โ€ข \(field): \(error)")
    }
}

์ถœ๋ ฅ:

โŒ ๊ฒ€์ฆ ์‹คํŒจ:
  โ€ข email: ์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค
  โ€ข password: ์ตœ์†Œ 8์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”

๐ŸŽฏ ์‚ฌ๋ก€ 2: ์ž๋™ ๋กœ๊น… ์‹œ์Šคํ…œ

enum LogLevel: String {
    case debug = "๐Ÿ”"
    case info = "โ„น๏ธ"
    case warning = "โš ๏ธ"
    case error = "โŒ"
}

class AutoLogger {
    
    static func log(_ object: Any, level: LogLevel = .info, context: String = "") {
        let timestamp = DateFormatter.localizedString(
            from: Date(),
            dateStyle: .none,
            timeStyle: .medium
        )
        
        print("\(level.rawValue) [\(timestamp)] \(context)")
        print(generateLogMessage(object, indent: 1))
        print(String(repeating: "โ”€", count: 50))
    }
    
    private static func generateLogMessage(_ object: Any, indent: Int) -> String {
        let mirror = Mirror(reflecting: object)
        let indentStr = String(repeating: "  ", count: indent)
        var message = ""
        
        if mirror.children.count == 0 {
            return "\(indentStr)\(object)"
        }
        
        message += "\(indentStr)Type: \(mirror.subjectType)\n"
        
        for child in mirror.children {
            let label = child.label ?? "value"
            let value = child.value
            let valueMirror = Mirror(reflecting: value)
            
            if valueMirror.children.count > 0 {
                message += "\(indentStr)\(label):\n"
                message += generateLogMessage(value, indent: indent + 1)
            } else {
                message += "\(indentStr)\(label): \(value)\n"
            }
        }
        
        return message
    }
}

// ์žฌ๋Šฅ๋„ท ๊ฑฐ๋ž˜ ์ •๋ณด
struct Transaction {
    let id: String
    let buyer: String
    let seller: String
    let amount: Int
    let status: String
    let timestamp: Date
}

let transaction = Transaction(
    id: "TXN-2024-001",
    buyer: "๊น€๊ตฌ๋งค์ž",
    seller: "์ดํŒ๋งค์ž",
    amount: 50000,
    status: "completed",
    timestamp: Date()
)

AutoLogger.log(transaction, level: .info, context: "๊ฑฐ๋ž˜ ์™„๋ฃŒ")

๐Ÿ”ฎ ๊ณ ๊ธ‰ ํŒจํ„ด: ์ปค์Šคํ…€ Mirror ๊ตฌํ˜„

์‚ฌ์‹ค Mirror๋Š” CustomReflectable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ์–ด! ์ด๊ฑธ ํ™œ์šฉํ•˜๋ฉด ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ˆจ๊ธฐ๊ฑฐ๋‚˜ ํŠน๋ณ„ํ•œ ํ‘œํ˜„ ๋ฐฉ์‹์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์ง€. ๐ŸŽญ

๐ŸŽจ CustomReflectable ํ™œ์šฉํ•˜๊ธฐ

struct SecureUser: CustomReflectable {
    let id: Int
    let username: String
    let email: String
    private let password: String
    private let apiKey: String
    
    // ์ปค์Šคํ…€ Mirror ์ •์˜
    var customMirror: Mirror {
        return Mirror(
            self,
            children: [
                "id": id,
                "username": username,
                "email": email,
                "password": "********",  // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ˆจ๊น€
                "apiKey": "********"     // API ํ‚ค ์ˆจ๊น€
            ],
            displayStyle: .struct
        )
    }
    
    init(id: Int, username: String, email: String, password: String, apiKey: String) {
        self.id = id
        self.username = username
        self.email = email
        self.password = password
        self.apiKey = apiKey
    }
}

let secureUser = SecureUser(
    id: 1,
    username: "secure_user",
    email: "user@example.com",
    password: "super_secret_password",
    apiKey: "sk_live_abc123xyz789"
)

// Mirror๋กœ ํ™•์ธํ•˜๋ฉด ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ์ˆจ๊ฒจ์ ธ ์žˆ์Œ
let mirror = Mirror(reflecting: secureUser)
print("๐Ÿ”’ ๋ณด์•ˆ ์‚ฌ์šฉ์ž ์ •๋ณด:")
for child in mirror.children {
    if let label = child.label {
        print("  \(label): \(child.value)")
    }
}

์ถœ๋ ฅ:

๐Ÿ”’ ๋ณด์•ˆ ์‚ฌ์šฉ์ž ์ •๋ณด:
  id: 1
  username: secure_user
  email: user@example.com
  password: ********
  apiKey: ********

์™„๋ฒฝํ•˜์ง€? ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋กœ๊น…์ด๋‚˜ ๋””๋ฒ„๊น… ์‹œ์—๋„ ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š์•„! ๐Ÿ›ก๏ธ

๐ŸŽ“ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ Mirror๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ! ๐Ÿ“š

โœ… ๊ถŒ์žฅ์‚ฌํ•ญ

1. ์ ์ ˆํ•œ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค ์„ ํƒ
โ€ข ๋””๋ฒ„๊น… ๋ฐ ๋กœ๊น…
โ€ข ๊ฐœ๋ฐœ ๋„๊ตฌ ์ œ์ž‘
โ€ข ๋ฒ”์šฉ ์ง๋ ฌํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
โ€ข ํ…Œ์ŠคํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ

2. ์„ฑ๋Šฅ ๊ณ ๋ ค
โ€ข ํ•ซ ํŒจ์Šค(์ž์ฃผ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ)์—์„œ๋Š” ์‚ฌ์šฉ ์ž์ œ
โ€ข ๊ฐ€๋Šฅํ•˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑ
โ€ข ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ๋ณด๋‹ค๋Š” ๊ฐœ๋ฐœ/๋””๋ฒ„๊น… ์šฉ๋„๋กœ

3. ํƒ€์ž… ์•ˆ์ „์„ฑ ์œ ์ง€
โ€ข ๊ฐ€๋Šฅํ•œ ํ•œ ์ œ๋„ค๋ฆญ๊ณผ ํ”„๋กœํ† ์ฝœ ํ™œ์šฉ
โ€ข Any ํƒ€์ž… ์‚ฌ์šฉ ์‹œ ํ•ญ์ƒ ํƒ€์ž… ์ฒดํฌ
โ€ข ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ ์ ๊ทน ํ™œ์šฉ

4. ๋ณด์•ˆ ๊ณ ๋ ค
โ€ข ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” CustomReflectable๋กœ ์ˆจ๊ธฐ๊ธฐ
โ€ข ๋กœ๊ทธ์— ๊ฐœ์ธ์ •๋ณด ๋…ธ์ถœ ์ฃผ์˜
โ€ข ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋กœ๊น… ๋ ˆ๋ฒจ ์กฐ์ •

โŒ ํ”ผํ•ด์•ผ ํ•  ๊ฒƒ๋“ค

1. ๊ณผ๋„ํ•œ ์˜์กด
Mirror์— ๋„ˆ๋ฌด ์˜์กดํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์ทจ์•ฝํ•ด์ ธ. ๊ฐ€๋Šฅํ•˜๋ฉด ์ •์  ํƒ€์ž… ์‹œ์Šคํ…œ์„ ํ™œ์šฉํ•˜์ž.

2. ํ”„๋กœ๋•์…˜ ํ•ต์‹ฌ ๋กœ์ง์— ์‚ฌ์šฉ
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์—์„œ๋Š” Mirror ์‚ฌ์šฉ์„ ํ”ผํ•˜์ž. ์„ฑ๋Šฅ๊ณผ ์•ˆ์ •์„ฑ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด.

3. ๊ฐ’ ์ˆ˜์ • ์‹œ๋„
Mirror๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด์•ผ. ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ์–ต์ง€๋กœ ์šฐํšŒํ•˜์ง€ ๋ง๊ณ  ์ ์ ˆํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ž.

4. ๋ณต์žกํ•œ ํƒ€์ž… ์ถ”๋ก 
์ œ๋„ค๋ฆญ์ด๋‚˜ ๋ณต์žกํ•œ ํƒ€์ž…์˜ ๊ฒฝ์šฐ Mirror๋งŒ์œผ๋กœ๋Š” ์™„์ „ํ•œ ํƒ€์ž… ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์–ด๋ ค์›Œ.

๐ŸŒŸ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ์™„์ „ํ•œ ๊ฐ์ฒด ๋น„๊ต ํ”„๋ ˆ์ž„์›Œํฌ

๋งˆ์ง€๋ง‰์œผ๋กœ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋ชจ๋“  ๋‚ด์šฉ์„ ํ™œ์šฉํ•ด์„œ ์™„์ „ํ•œ ๊ฐ์ฒด ๋น„๊ต ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ์ด๊ฑด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•  ๊ฑฐ์•ผ. ๐Ÿš€

๐ŸŽฏ ์™„์„ฑ๋„ ๋†’์€ ๋น„๊ต ํ”„๋ ˆ์ž„์›Œํฌ

struct ComparisonResult {
    let isEqual: Bool
    let differences: [String]
    
    var description: String {
        if isEqual {
            return "โœ… ๊ฐ์ฒด๊ฐ€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค"
        } else {
            var result = "โŒ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค\n์ฐจ์ด์ :\n"
            for diff in differences {
                result += "  โ€ข \(diff)\n"
            }
            return result
        }
    }
}

class ObjectComparator {
    
    static func compare(_ lhs: Any, _ rhs: Any, path: String = "root") -> ComparisonResult {
        var differences: [String] = []
        
        let lhsMirror = Mirror(reflecting: lhs)
        let rhsMirror = Mirror(reflecting: rhs)
        
        // ํƒ€์ž… ๋น„๊ต
        if lhsMirror.subjectType != rhsMirror.subjectType {
            differences.append("\(path): ํƒ€์ž… ๋ถˆ์ผ์น˜ (\(lhsMirror.subjectType) != \(rhsMirror.subjectType))")
            return ComparisonResult(isEqual: false, differences: differences)
        }
        
        // ์ž์‹์ด ์—†๋Š” ๊ฒฝ์šฐ (๊ธฐ๋ณธ ํƒ€์ž…)
        if lhsMirror.children.count == 0 {
            if !areValuesEqual(lhs, rhs) {
                differences.append("\(path): ๊ฐ’ ๋ถˆ์ผ์น˜ (\(lhs) != \(rhs))")
            }
            return ComparisonResult(isEqual: differences.isEmpty, differences: differences)
        }
        
        // ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜ ๋น„๊ต
        if lhsMirror.children.count != rhsMirror.children.count {
            differences.append("\(path): ํ”„๋กœํผํ‹ฐ ๊ฐœ์ˆ˜ ๋ถˆ์ผ์น˜")
            return ComparisonResult(isEqual: false, differences: differences)
        }
        
        // ๊ฐ ํ”„๋กœํผํ‹ฐ ๋น„๊ต
        let lhsChildren = Array(lhsMirror.children)
        let rhsChildren = Array(rhsMirror.children)
        
        for (index, lhsChild) in lhsChildren.enumerated() {
            let rhsChild = rhsChildren[index]
            let label = lhsChild.label ?? "[\(index)]"
            let newPath = "\(path).\(label)"
            
            // ๋ ˆ์ด๋ธ” ๋น„๊ต
            if lhsChild.label != rhsChild.label {
                differences.append("\(newPath): ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„ ๋ถˆ์ผ์น˜")
                continue
            }
            
            // ์žฌ๊ท€์ ์œผ๋กœ ๊ฐ’ ๋น„๊ต
            let childResult = compare(lhsChild.value, rhsChild.value, path: newPath)
            differences.append(contentsOf: childResult.differences)
        }
        
        return ComparisonResult(isEqual: differences.isEmpty, differences: differences)
    }
    
    private static func areValuesEqual(_ lhs: Any, _ rhs: Any) -> Bool {
        // String ๋น„๊ต
        if let lhsString = lhs as? String, let rhsString = rhs as? String {
            return lhsString == rhsString
        }
        
        // Int ๋น„๊ต
        if let lhsInt = lhs as? Int, let rhsInt = rhs as? Int {
            return lhsInt == rhsInt
        }
        
        // Double ๋น„๊ต
        if let lhsDouble = lhs as? Double, let rhsDouble = rhs as? Double {
            return abs(lhsDouble - rhsDouble) < 0.0001
        }
        
        // Bool ๋น„๊ต
        if let lhsBool = lhs as? Bool, let rhsBool = rhs as? Bool {
            return lhsBool == rhsBool
        }
        
        // ๋ฐฐ์—ด ๋น„๊ต
        if let lhsArray = lhs as? [Any], let rhsArray = rhs as? [Any] {
            if lhsArray.count != rhsArray.count { return false }
            for (l, r) in zip(lhsArray, rhsArray) {
                if !areValuesEqual(l, r) { return false }
            }
            return true
        }
        
        // ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฌธ์ž์—ด ํ‘œํ˜„ ๋น„๊ต
        return "\(lhs)" == "\(rhs)"
    }
}

// ํ…Œ์ŠคํŠธ
struct UserProfile {
    let name: String
    let age: Int
    let email: String
    let preferences: Preferences
}

struct Preferences {
    let theme: String
    let notifications: Bool
    let language: String
}

let profile1 = UserProfile(
    name: "๊น€์ฒ ์ˆ˜",
    age: 28,
    email: "chulsoo@example.com",
    preferences: Preferences(
        theme: "dark",
        notifications: true,
        language: "ko"
    )
)

let profile2 = UserProfile(
    name: "๊น€์ฒ ์ˆ˜",
    age: 29,  // ๋‹ค๋ฆ„!
    email: "chulsoo@example.com",
    preferences: Preferences(
        theme: "light",  // ๋‹ค๋ฆ„!
        notifications: true,
        language: "ko"
    )
)

let result = ObjectComparator.compare(profile1, profile2)
print(result.description)

์ถœ๋ ฅ:

โŒ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค
์ฐจ์ด์ :
  โ€ข root.age: ๊ฐ’ ๋ถˆ์ผ์น˜ (28 != 29)
  โ€ข root.preferences.theme: ๊ฐ’ ๋ถˆ์ผ์น˜ (dark != light)

์™„๋ฒฝํ•˜์ง€? ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ๊ตฌ์กฐ์—์„œ๋„ ์ •ํ™•ํžˆ ์–ด๋–ค ๋ถ€๋ถ„์ด ๋‹ค๋ฅธ์ง€ ์•Œ๋ ค์ค˜! ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์–ด. ๐ŸŽ‰

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ Swift์˜ ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ Mirror์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ์•Œ์•„๋ดค์–ด! ๐ŸŽŠ

์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ผ๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋  ๊ฑฐ์•ผ. ํŠนํžˆ ๋””๋ฒ„๊น… ๋„๊ตฌ๋‚˜ ํ…Œ์ŠคํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๋งŒ๋“ค ๋•Œ, ๋˜๋Š” ๋ฒ”์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ Mirror๋Š” ์—†์–ด์„œ๋Š” ์•ˆ ๋  ์กด์žฌ์ง€! ๐Ÿ’ช

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ

1. Mirror์˜ ๋ณธ์งˆ
๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด์˜ ๊ตฌ์กฐ๋ฅผ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ๋„๊ตฌ

2. ์ฃผ์š” ๊ธฐ๋Šฅ
โ€ข children: ํ”„๋กœํผํ‹ฐ ์ˆœํšŒ
โ€ข displayStyle: ํƒ€์ž… ์ข…๋ฅ˜ ํŒŒ์•…
โ€ข superclassMirror: ์ƒ์† ๊ตฌ์กฐ ํƒ์ƒ‰
โ€ข CustomReflectable: ์ปค์Šคํ…€ ํ‘œํ˜„

3. ํ™œ์šฉ ๋ถ„์•ผ
โ€ข ๋””๋ฒ„๊น… ๋ฐ ๋กœ๊น…
โ€ข ๊ฐ์ฒด ์ง๋ ฌํ™”
โ€ข ํ…Œ์ŠคํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ
โ€ข ํผ ๊ฒ€์ฆ ์‹œ์Šคํ…œ

4. ์ฃผ์˜์‚ฌํ•ญ
โ€ข ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ ๊ณ ๋ ค
โ€ข ์ฝ๊ธฐ ์ „์šฉ ํŠน์„ฑ
โ€ข ํƒ€์ž… ์•ˆ์ „์„ฑ ์œ ์ง€
โ€ข ๋ณด์•ˆ ์ •๋ณด ๋ณดํ˜ธ

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๊ฑฐ๋‚˜, ๋ณต์žกํ•œ iOS ์•ฑ์„ ๋งŒ๋“ค ๋•Œ Mirror๋Š” ์ •๋ง ์œ ์šฉํ•œ ๋„๊ตฌ๊ฐ€ ๋  ๊ฑฐ์•ผ. ํŠนํžˆ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ฑฐ๋‚˜, ๋™์ ์ธ UI๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, ๋””๋ฒ„๊น… ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค ๋•Œ ๋น›์„ ๋ฐœํ•˜์ง€! โœจ

๋ฌผ๋ก  ๋ชจ๋“  ์ƒํ™ฉ์—์„œ Mirror๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์–ด. ๋•Œ๋กœ๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‚˜ ์ œ๋„ค๋ฆญ, Codable ๊ฐ™์€ ๋‹ค๋ฅธ Swift ๊ธฐ๋Šฅ๋“ค์ด ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ์ค‘์š”ํ•œ ๊ฑด ๊ฐ ๋„๊ตฌ์˜ ํŠน์„ฑ์„ ์ดํ•ดํ•˜๊ณ , ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ ์ ˆํžˆ ์„ ํƒํ•˜๋Š” ๊ฑฐ์•ผ! ๐ŸŽฏ

Swift Mirror Reflection Mastery Debug Tools Testing Framework Logging System Validation Engine

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„๋„ Swift Mirror ๋งˆ์Šคํ„ฐ๊ฐ€ ๋์–ด! ๐ŸŽ“

์•ž์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ "์ด ๊ฐ์ฒด ์•ˆ์— ๋ญ๊ฐ€ ๋“ค์–ด์žˆ์ง€?", "๋Ÿฐํƒ€์ž„์— ํƒ€์ž…์„ ํ™•์ธํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜์ง€?" ๊ฐ™์€ ๊ณ ๋ฏผ์ด ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค Mirror๋ฅผ ๋– ์˜ฌ๋ ค๋ด. ๋ถ„๋ช… ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ! ๐Ÿ’ก

๊ทธ๋ฆฌ๊ณ  ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์œผ๋‹ˆ, Swift ๊ฐœ๋ฐœ์— ๊ด€์‹ฌ ์žˆ๋‹ค๋ฉด ํ•œ๋ฒˆ ๋‘˜๋Ÿฌ๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„. ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ๋‹ˆ๊นŒ! ๐ŸŒฑ

๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ

Mirror๋ฅผ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด ์ด๋Ÿฐ ๊ฒƒ๋“ค๋„ ๊ณต๋ถ€ํ•ด๋ณด๋ฉด ์ข‹์•„:
โ€ข KeyPath: ํƒ€์ž… ์•ˆ์ „ํ•œ ํ”„๋กœํผํ‹ฐ ์ ‘๊ทผ
โ€ข Codable: ๊ฐ•๋ ฅํ•œ ์ง๋ ฌํ™” ์‹œ์Šคํ…œ
โ€ข Property Wrappers: ํ”„๋กœํผํ‹ฐ ๋™์ž‘ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
โ€ข Result Builders: DSL ๋งŒ๋“ค๊ธฐ
โ€ข Metatypes: ํƒ€์ž…์˜ ํƒ€์ž… ๋‹ค๋ฃจ๊ธฐ

Happy Coding! ๐ŸŽ‰โœจ
Mirror๋กœ ๋” ๋‚˜์€ Swift ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”!

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.