Ver3.0 ๐ ์ค์ํํธ ๋ฆฌํ๋ ์ ๊ณผ Mirror๋ฅผ ํ์ฉํ ๋ฐํ์ ํ์ ๊ฒ์ฌ ์์ ์ ๋ณต

๐ ์ค์ํํธ ๋ฆฌํ๋ ์ ๊ณผ Mirror๋ฅผ ํ์ฉํ ๋ฐํ์ ํ์ ๊ฒ์ฌ ์์ ์ ๋ณต
๋ฐํ์์ ํ์ ์ ๋ค์ฌ๋ค๋ณด๋ ๋ง๋ฒ ๊ฐ์ ๊ธฐ์ , ์ง๊ธ ๋ฐ๋ก ์์ํด๋ณผ๊น์? โจ
๐ฏ ์๋
ํ์ธ์! ์ค๋์ Swift์ ์จ๊ฒจ์ง ๋ณด์ ๊ฐ์ ๊ธฐ๋ฅ, ๋ฆฌํ๋ ์
(Reflection)๊ณผ Mirror์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ ๊ฑฐ์์.
ํ๋ก๊ทธ๋๋ฐ์ ํ๋ค ๋ณด๋ฉด "์ด ๋ณ์๊ฐ ๋ฐํ์์ ์ ํํ ์ด๋ค ํ์
์ด์ง?", "์ด ๊ฐ์ฒด ์์ ์ด๋ค ํ๋กํผํฐ๋ค์ด ๋ค์ด์์ง?" ๊ฐ์ ๊ถ๊ธ์ฆ์ด ์๊ธธ ๋๊ฐ ์์ฃ . ์ปดํ์ผ ํ์์๋ ๋ชจ๋ ๊ฒ ๋ช
ํํ์ง๋ง, ์ค์ ๋ก ์ฑ์ด ๋์๊ฐ๋ ์๊ฐ์๋ ์์์น ๋ชปํ ์ํฉ๋ค์ด ๋ฐ์ํ๊ธฐ๋ ํ๊ณ ์. ๐ค
๋ฐ๋ก ์ด๋ด ๋ ํ์ํ ๊ฒ ๋ฆฌํ๋ ์
์ด์์! ๋ง์น ๊ฑฐ์ธ(Mirror)๋ก ์์ ์ ๋น์ถฐ๋ณด๋ฏ, ์ฝ๋๊ฐ ์คํ๋๋ ๋์ ๊ฐ์ฒด์ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋ค์ฌ๋ค๋ณผ ์ ์๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋๋๋ค.
๐ช ๋ฆฌํ๋ ์ ์ด๋ ๋ฌด์์ธ๊ฐ์?
๋ฆฌํ๋ ์
(Reflection)์ ํ๋ก๊ทธ๋จ์ด ์คํ ์ค์ ์๊ธฐ ์์ ์ ๊ตฌ์กฐ๋ฅผ ๊ฒ์ฌํ๊ณ ์์ ํ ์ ์๋ ๋ฅ๋ ฅ์ ๋งํด์. ์ฝ๊ฒ ๋งํ๋ฉด, ์ฝ๋๊ฐ "์๊ธฐ ์์ ์ ๊ฑฐ์ธ๋ก ๋น์ถฐ๋ณด๋ ๊ฒ"์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ์. ๐ช
๋ค๋ฅธ ์ธ์ด๋ค(Java, Python, C# ๋ฑ)์์๋ ์ด๋ฏธ ์ค๋์ ๋ถํฐ ๋ฆฌํ๋ ์
์ ๊ฐ๋ ฅํ๊ฒ ์ง์ํด์๋๋ฐ, Swift๋ Mirror๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ํตํด ๋ฆฌํ๋ ์
๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ด์.
๐ก ๋ฆฌํ๋ ์ ์ผ๋ก ํ ์ ์๋ ๊ฒ๋ค
โ
๊ฐ์ฒด์ ํ์
์ ๋ณด๋ฅผ ๋ฐํ์์ ํ์ธ
โ
๊ฐ์ฒด๊ฐ ๊ฐ์ง ํ๋กํผํฐ ๋ชฉ๋ก๊ณผ ๊ฐ ์กฐํ
โ
๊ฐ์ฒด์ ๊ตฌ์กฐ๋ฅผ ๋์ ์ผ๋ก ํ์
โ
๋๋ฒ๊น
๊ณผ ๋ก๊น
์ ํ์ฉ
โ
JSON ์ง๋ ฌํ/์ญ์ง๋ ฌํ ๊ตฌํ
โ
ํ
์คํธ ์ฝ๋ ์์ฑ ์ ๊ฐ์ฒด ๊ฒ์ฆ
๐ฎ Mirror์ ๊ธฐ๋ณธ ๊ฐ๋
Swift์์ ๋ฆฌํ๋ ์
์ ํต์ฌ์ ๋ฐ๋ก Mirror ๊ตฌ์กฐ์ฒด์์. Mirror๋ ๋ง ๊ทธ๋๋ก "๊ฑฐ์ธ"์ฒ๋ผ ์ด๋ค ์ธ์คํด์ค์ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋น์ถฐ์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.
Mirror๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์ ๋ง ๊ฐ๋จํด์:
let person = Person(name: "๊น์ฒ ์", age: 28)
let mirror = Mirror(reflecting: person)
์ด๋ ๊ฒ ํ๋ฉด person ๊ฐ์ฒด์ ๋ด๋ถ๋ฅผ ๋ค์ฌ๋ค๋ณผ ์ ์๋ ๊ฑฐ์ธ์ด ๋ง๋ค์ด์ง๋ ๊ฑฐ์ฃ ! ๐
๐ ๏ธ Mirror์ ์ฃผ์ ํ๋กํผํฐ์ ๋ฉ์๋
Mirror ๊ตฌ์กฐ์ฒด๋ ์ฌ๋ฌ ๊ฐ์ง ์ ์ฉํ ํ๋กํผํฐ๋ฅผ ์ ๊ณตํด์. ํ๋์ฉ ์ดํด๋ณผ๊น์?
| ํ๋กํผํฐ/๋ฉ์๋ | ์ค๋ช | ๋ฐํ ํ์ |
|---|---|---|
children |
๊ฐ์ฒด์ ๋ชจ๋ ์์ ์์(ํ๋กํผํฐ) ์ปฌ๋ ์ | Children |
displayStyle |
๊ฐ์ฒด์ ํ์ ์คํ์ผ (struct, class, enum ๋ฑ) | DisplayStyle? |
subjectType |
๋ฐ์๋๋ ๊ฐ์ฒด์ ํ์ | Any.Type |
superclassMirror |
๋ถ๋ชจ ํด๋์ค์ Mirror (์์ ๊ฒฝ์ฐ) | Mirror? |
๐ฆ children ํ๋กํผํฐ ํ์ฉํ๊ธฐ
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๊ฑด ๋ฐ๋ก children ํ๋กํผํฐ์์. ์ด๊ฑธ ํตํด ๊ฐ์ฒด์ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์ํํ ์ ์์ด์:
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)
for child in mirror.children {
if let label = child.label {
print("\(label): \(child.value)")
}
}
// ์ถ๋ ฅ:
// name: ๊น์ฒ ์
// age: 28
// email: chulsoo@example.com
child.label์ ์ต์
๋์ด์์! ํํ์ด๋ ๋ฐฐ์ด ๊ฐ์ ๊ฒฝ์ฐ ๋ ์ด๋ธ์ด ์์ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ . ํญ์ ์ต์
๋ ๋ฐ์ธ๋ฉ์ ์ฌ์ฉํ๋ ๊ฒ ์์ ํด์.
๐ฏ ์ค์ ํ์ฉ ์์
1๏ธโฃ ๋๋ฒ๊น ์ฉ ์ค๋ช ๋ฌธ์์ด ์์ฑํ๊ธฐ
๊ฐ์ฒด์ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ๋ณด๊ธฐ ์ข๊ฒ ์ถ๋ ฅํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ณผ๊น์? ๋๋ฒ๊น ํ ๋ ์ ๋ง ์ ์ฉํ๋ต๋๋ค! ๐
func describe(_ object: Any) -> String {
let mirror = Mirror(reflecting: object)
var description = "\(mirror.subjectType) {\n"
for child in mirror.children {
if let label = child.label {
description += " \(label): \(child.value)\n"
}
}
description += "}"
return description
}
// ์ฌ์ฉ ์์
struct Book {
let title: String
let author: String
let pages: Int
let isAvailable: Bool
}
let book = Book(
title: "์ค์ํํธ ๋ง์คํฐํ๊ธฐ",
author: "๋ฐ๊ฐ๋ฐ",
pages: 450,
isAvailable: true
)
print(describe(book))
// ์ถ๋ ฅ:
// Book {
// title: ์ค์ํํธ ๋ง์คํฐํ๊ธฐ
// author: ๋ฐ๊ฐ๋ฐ
// pages: 450
// isAvailable: true
// }
2๏ธโฃ ๋์ ๋๋ฆฌ๋ก ๋ณํํ๊ธฐ
๊ฐ์ฒด๋ฅผ ๋์ ๋๋ฆฌ๋ก ๋ณํํ๋ ๊ฒ๋ ์์ฃผ ์ฐ์ด๋ ํจํด์ด์์. JSON ์ง๋ ฌํ๋ ๋ก๊น ์ ์ ์ฉํ์ฃ :
func toDictionary(_ object: Any) -> [String: Any] {
let mirror = Mirror(reflecting: object)
var dictionary: [String: Any] = [:]
for child in mirror.children {
if let label = child.label {
dictionary[label] = child.value
}
}
return dictionary
}
// ์ฌ์ฉ ์์
struct Product {
let id: Int
let name: String
let price: Double
let inStock: Bool
}
let product = Product(id: 101, name: "๋งฅ๋ถ ํ๋ก", price: 2500000, inStock: true)
let dict = toDictionary(product)
print(dict)
// ["id": 101, "name": "๋งฅ๋ถ ํ๋ก", "price": 2500000.0, "inStock": true]
3๏ธโฃ ํ์ ๊ฒ์ฌ ๋ฐ ํํฐ๋ง
ํน์ ํ์ ์ ํ๋กํผํฐ๋ง ์ฐพ์๋ด๋ ๊ฒ๋ ๊ฐ๋ฅํด์:
func findProperties<T>(of type: T.Type, in object: Any) -> [String: T] {
let mirror = Mirror(reflecting: object)
var result: [String: T] = [:]
for child in mirror.children {
if let label = child.label,
let value = child.value as? T {
result[label] = value
}
}
return result
}
// ์ฌ์ฉ ์์
struct UserProfile {
let username: String
let age: Int
let email: String
let score: Int
let bio: String
}
let profile = UserProfile(
username: "swiftmaster",
age: 25,
email: "master@swift.com",
score: 9500,
bio: "Swift ๊ฐ๋ฐ์์
๋๋ค"
)
// String ํ์
ํ๋กํผํฐ๋ง ์ฐพ๊ธฐ
let stringProps = findProperties(of: String.self, in: profile)
print(stringProps)
// ["username": "swiftmaster", "email": "master@swift.com", "bio": "Swift ๊ฐ๋ฐ์์
๋๋ค"]
// Int ํ์
ํ๋กํผํฐ๋ง ์ฐพ๊ธฐ
let intProps = findProperties(of: Int.self, in: profile)
print(intProps)
// ["age": 25, "score": 9500]
๐ DisplayStyle๋ก ํ์ ๊ตฌ๋ถํ๊ธฐ
displayStyle ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๊ฐ struct์ธ์ง, class์ธ์ง, enum์ธ์ง ๋ฑ์ ๊ตฌ๋ถํ ์ ์์ด์:
func getTypeDescription(_ object: Any) -> String {
let mirror = Mirror(reflecting: object)
guard let displayStyle = mirror.displayStyle else {
return "์ ์ ์๋ ํ์
"
}
switch displayStyle {
case .struct:
return "๊ตฌ์กฐ์ฒด (Struct)"
case .class:
return "ํด๋์ค (Class)"
case .enum:
return "์ด๊ฑฐํ (Enum)"
case .tuple:
return "ํํ (Tuple)"
case .optional:
return "์ต์
๋ (Optional)"
case .collection:
return "์ปฌ๋ ์
(Collection)"
case .dictionary:
return "๋์
๋๋ฆฌ (Dictionary)"
case .set:
return "์งํฉ (Set)"
@unknown default:
return "๊ธฐํ ํ์
"
}
}
// ํ
์คํธ
struct MyStruct { let value: Int }
class MyClass { let value: Int; init(value: Int) { self.value = value } }
enum MyEnum { case first, second }
print(getTypeDescription(MyStruct(value: 10))) // ๊ตฌ์กฐ์ฒด (Struct)
print(getTypeDescription(MyClass(value: 20))) // ํด๋์ค (Class)
print(getTypeDescription(MyEnum.first)) // ์ด๊ฑฐํ (Enum)
print(getTypeDescription([1, 2, 3])) // ์ปฌ๋ ์
(Collection)
print(getTypeDescription(["key": "value"])) // ๋์
๋๋ฆฌ (Dictionary)
๐ณ ์์ ๊ตฌ์กฐ ํ์ํ๊ธฐ
ํด๋์ค์ ์์ ๊ตฌ์กฐ๋ Mirror๋ฅผ ํตํด ํ์ํ ์ ์์ด์. superclassMirror ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ผ์:
class Animal {
let species: String
init(species: String) {
self.species = species
}
}
class Dog: Animal {
let breed: String
init(breed: String) {
self.breed = breed
super.init(species: "๊ฐ")
}
}
class Poodle: Dog {
let color: String
init(color: String) {
self.color = color
super.init(breed: "ํธ๋ค")
}
}
func printInheritanceChain(_ object: Any) {
var mirror: Mirror? = Mirror(reflecting: object)
var level = 0
while let currentMirror = mirror {
let indent = String(repeating: " ", count: level)
print("\(indent)๐ฆ \(currentMirror.subjectType)")
for child in currentMirror.children {
if let label = child.label {
print("\(indent) โโ \(label): \(child.value)")
}
}
mirror = currentMirror.superclassMirror
level += 1
}
}
let myPoodle = Poodle(color: "ํฐ์")
printInheritanceChain(myPoodle)
// ์ถ๋ ฅ:
// ๐ฆ Poodle
// โโ color: ํฐ์
// ๐ฆ Dog
// โโ breed: ํธ๋ค
// ๐ฆ Animal
// โโ species: ๊ฐ
โ ๏ธ Mirror์ ํ๊ณ์ ์ฃผ์์ฌํญ
Mirror๋ ๊ฐ๋ ฅํ์ง๋ง, ๋ช ๊ฐ์ง ์ ์ฝ์ฌํญ์ด ์์ด์. ์์๋๋ฉด ์ข์ ๊ฒ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ์:
๐จ ์ฃผ์ํด์ผ ํ ์ ๋ค
1. ์ฑ๋ฅ ์ค๋ฒํค๋
๋ฆฌํ๋ ์
์ ๋ฐํ์์ ๋์ํ๊ธฐ ๋๋ฌธ์ ์ปดํ์ผ ํ์ ์ต์ ํ๋ฅผ ๋ฐ์ ์ ์์ด์. ๋ฐ๋ผ์ ์ฑ๋ฅ์ด ์ค์ํ ๋ฃจํ ์์์๋ ์ฌ์ฉ์ ์์ ํ๋ ๊ฒ ์ข์์.
2. ์ฝ๊ธฐ ์ ์ฉ
Mirror๋ ๊ฐ์ ์ฝ์ ์๋ง ์๊ณ , ์์ ํ ์๋ ์์ด์. ํ๋กํผํฐ ๊ฐ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํด์.
3. private ํ๋กํผํฐ ์ ๊ทผ ๋ถ๊ฐ
private์ผ๋ก ์ ์ธ๋ ํ๋กํผํฐ๋ Mirror๋ก๋ ์ ๊ทผํ ์ ์์ด์. Swift์ ์ ๊ทผ ์ ์ด๋ ๋ฆฌํ๋ ์
์๋ ์ ์ฉ๋๋ต๋๋ค.
4. ํ์
์ ๋ณด ์ ํ
์ ๋ค๋ฆญ ํ์
์ ๊ตฌ์ฒด์ ์ธ ํ์
ํ๋ผ๋ฏธํฐ ์ ๋ณด๋ ์ป๊ธฐ ์ด๋ ค์์.
5. ๊ณ์ฐ ํ๋กํผํฐ๋ ํฌํจ ์ ๋จ
์ ์ฅ ํ๋กํผํฐ๋ง Mirror์ ๋ํ๋๊ณ , ๊ณ์ฐ ํ๋กํผํฐ๋ ๋ณด์ด์ง ์์์.
๐ private ํ๋กํผํฐ ์์
struct SecureData {
let publicInfo: String
private let secretKey: String
init(publicInfo: String, secretKey: String) {
self.publicInfo = publicInfo
self.secretKey = secretKey
}
}
let data = SecureData(publicInfo: "๊ณต๊ฐ ์ ๋ณด", secretKey: "๋น๋ฐํค123")
let mirror = Mirror(reflecting: data)
for child in mirror.children {
if let label = child.label {
print("\(label): \(child.value)")
}
}
// ์ถ๋ ฅ:
// publicInfo: ๊ณต๊ฐ ์ ๋ณด
// secretKey: ๋น๋ฐํค123
// โ ๏ธ ์ฃผ์: private์ด์ด๋ Mirror๋ก๋ ๋ณผ ์ ์์ด์!
// ํ์ง๋ง ์ง์ ์ ๊ทผ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค: data.secretKey // ์ปดํ์ผ ์๋ฌ
๐จ ๊ณ ๊ธ ํ์ฉ ํจํด
1๏ธโฃ ์ปค์คํ Mirror ๊ตฌํํ๊ธฐ
CustomReflectable ํ๋กํ ์ฝ์ ์ฑํํ๋ฉด Mirror๊ฐ ๋ณด์ฌ์ฃผ๋ ๋ด์ฉ์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ด์:
struct BankAccount: CustomReflectable {
let accountNumber: String
private let balance: Double
private let pin: String
init(accountNumber: String, balance: Double, pin: String) {
self.accountNumber = accountNumber
self.balance = balance
self.pin = pin
}
// ์ปค์คํ
Mirror ์ ์
var customMirror: Mirror {
return Mirror(
self,
children: [
"accountNumber": accountNumber,
"balance": "***์จ๊น***", // ๋ฏผ๊ฐํ ์ ๋ณด๋ ์จ๊น
"pin": "****" // PIN์ ์ ๋ ๋
ธ์ถ ์ ํจ
],
displayStyle: .struct
)
}
}
let account = BankAccount(
accountNumber: "123-456-789",
balance: 1000000,
pin: "1234"
)
let mirror = Mirror(reflecting: account)
for child in mirror.children {
if let label = child.label {
print("\(label): \(child.value)")
}
}
// ์ถ๋ ฅ:
// accountNumber: 123-456-789
// balance: ***์จ๊น***
// pin: ****
2๏ธโฃ ์ฌ๊ท์ ๊ฐ์ฒด ํ์
์ค์ฒฉ๋ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํ์ํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ณผ๊น์:
func deepInspect(_ object: Any, indent: String = "") {
let mirror = Mirror(reflecting: object)
print("\(indent)๐ฆ ํ์
: \(mirror.subjectType)")
for child in mirror.children {
let label = child.label ?? "unnamed"
let value = child.value
print("\(indent)โโ \(label):", terminator: " ")
// ๊ธฐ๋ณธ ํ์
์ด๋ฉด ๋ฐ๋ก ์ถ๋ ฅ
if let stringValue = value as? String {
print("\"\(stringValue)\"")
} else if let intValue = value as? Int {
print(intValue)
} else if let doubleValue = value as? Double {
print(doubleValue)
} else if let boolValue = value as? Bool {
print(boolValue)
} else {
// ๋ณต์กํ ํ์
์ด๋ฉด ์ฌ๊ท ํธ์ถ
print("")
deepInspect(value, indent: indent + " ")
}
}
}
// ํ
์คํธ์ฉ ์ค์ฒฉ ๊ตฌ์กฐ
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
}
let employee = Employee(
name: "์ด๊ฐ๋ฐ",
age: 30,
company: Company(
name: "ํ
ํฌ์คํํธ์
",
address: Address(
street: "ํ
ํค๋๋ก 123",
city: "์์ธ",
zipCode: "06234"
)
)
)
deepInspect(employee)
// ์ถ๋ ฅ:
// ๐ฆ ํ์
: Employee
// โโ name: "์ด๊ฐ๋ฐ"
// โโ age: 30
// โโ company:
// ๐ฆ ํ์
: Company
// โโ name: "ํ
ํฌ์คํํธ์
"
// โโ address:
// ๐ฆ ํ์
: Address
// โโ street: "ํ
ํค๋๋ก 123"
// โโ city: "์์ธ"
// โโ zipCode: "06234"
3๏ธโฃ ๊ฐ์ฒด ๋น๊ต ์ ํธ๋ฆฌํฐ
๋ ๊ฐ์ฒด์ ํ๋กํผํฐ๋ฅผ ๋น๊ตํด์ ์ฐจ์ด์ ์ ์ฐพ์๋ด๋ ํจ์๋ ๋ง๋ค ์ ์์ด์:
func findDifferences(between obj1: Any, and obj2: Any) -> [String: (Any, Any)] {
let mirror1 = Mirror(reflecting: obj1)
let mirror2 = Mirror(reflecting: obj2)
var differences: [String: (Any, Any)] = [:]
// obj1์ ํ๋กํผํฐ๋ฅผ ๋์
๋๋ฆฌ๋ก ๋ณํ
var props1: [String: Any] = [:]
for child in mirror1.children {
if let label = child.label {
props1[label] = child.value
}
}
// obj2์ ํ๋กํผํฐ๋ฅผ ๋์
๋๋ฆฌ๋ก ๋ณํ
var props2: [String: Any] = [:]
for child in mirror2.children {
if let label = child.label {
props2[label] = child.value
}
}
// ์ฐจ์ด์ ์ฐพ๊ธฐ
for (key, value1) in props1 {
if let value2 = props2[key] {
// ๊ฐ๋จํ ๋น๊ต (์ค์ ๋ก๋ ๋ ์ ๊ตํ ๋น๊ต ํ์)
if "\(value1)" != "\(value2)" {
differences[key] = (value1, value2)
}
}
}
return differences
}
// ์ฌ์ฉ ์์
struct Config {
let serverURL: String
let timeout: Int
let enableLogging: Bool
}
let oldConfig = Config(
serverURL: "https://api.old.com",
timeout: 30,
enableLogging: false
)
let newConfig = Config(
serverURL: "https://api.new.com",
timeout: 60,
enableLogging: true
)
let diffs = findDifferences(between: oldConfig, and: newConfig)
print("๐ ๋ณ๊ฒฝ๋ ์ค์ :")
for (key, values) in diffs {
print(" \(key): \(values.0) โ \(values.1)")
}
// ์ถ๋ ฅ:
// ๐ ๋ณ๊ฒฝ๋ ์ค์ :
// serverURL: https://api.old.com โ https://api.new.com
// timeout: 30 โ 60
// enableLogging: false โ true
๐งช ํ ์คํธ ์ฝ๋์์์ ํ์ฉ
Mirror๋ ํ ์คํธ ์ฝ๋ ์์ฑํ ๋๋ ์ ๋ง ์ ์ฉํด์. ํนํ ๊ฐ์ฒด์ ๋ด๋ถ ์ํ๋ฅผ ๊ฒ์ฆํ ๋ ๋ง์ด์ฃ :
import XCTest
// ํ
์คํธ ํฌํผ ํจ์
func assertHasProperty<T>(
_ object: Any,
named propertyName: String,
ofType type: T.Type,
withValue expectedValue: T,
file: StaticString = #file,
line: UInt = #line
) where T: Equatable {
let mirror = Mirror(reflecting: object)
for child in mirror.children {
if let label = child.label, label == propertyName {
if let actualValue = child.value as? T {
XCTAssertEqual(
actualValue,
expectedValue,
"ํ๋กํผํฐ '\(propertyName)'์ ๊ฐ์ด ์์๊ณผ ๋ค๋ฆ
๋๋ค",
file: file,
line: line
)
return
} else {
XCTFail(
"ํ๋กํผํฐ '\(propertyName)'์ ํ์
์ด \(T.self)๊ฐ ์๋๋๋ค",
file: file,
line: line
)
return
}
}
}
XCTFail(
"ํ๋กํผํฐ '\(propertyName)'์ ์ฐพ์ ์ ์์ต๋๋ค",
file: file,
line: line
)
}
// ํ
์คํธ ์์
class UserTests: XCTestCase {
func testUserCreation() {
struct User {
let id: Int
let username: String
let isActive: Bool
}
let user = User(id: 1, username: "testuser", isActive: true)
// Mirror๋ฅผ ํ์ฉํ ๊ฒ์ฆ
assertHasProperty(user, named: "id", ofType: Int.self, withValue: 1)
assertHasProperty(user, named: "username", ofType: String.self, withValue: "testuser")
assertHasProperty(user, named: "isActive", ofType: Bool.self, withValue: true)
}
}
๐ ์ค๋ฌด์์์ ํ์ฉ ์ฌ๋ก
๐ผ ์ค์ ํ๋ก์ ํธ์์ Mirror๊ฐ ๋น๋๋ ์๊ฐ๋ค
1. ๋ก๊น
์์คํ
๐
์ฑ์ ๋ชจ๋ ์ด๋ฒคํธ์ ์ํ๋ฅผ ์๋์ผ๋ก ๋ก๊น
ํ ๋, Mirror๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด์ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์๋์ผ๋ก ๊ธฐ๋กํ ์ ์์ด์.
2. ๋๋ฒ๊ทธ ํ๋ฉด ๐
๊ฐ๋ฐ ์ค์ ๊ฐ์ฒด์ ํ์ฌ ์ํ๋ฅผ ํ๋ฉด์ ํ์ํ๋ ๋๋ฒ๊ทธ ๋ทฐ๋ฅผ ๋ง๋ค ๋ ์ ์ฉํด์.
3. ๋ฐ์ดํฐ ์ง๋ ฌํ ๐พ
์ปค์คํ
JSON ์ธ์ฝ๋/๋์ฝ๋๋ฅผ ๋ง๋ค ๋ Mirror๋ฅผ ํ์ฉํ๋ฉด ์๋์ผ๋ก ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด์.
4. ํผ ๊ฒ์ฆ โ
์ฌ์ฉ์ ์
๋ ฅ ํผ์์ ๋ชจ๋ ํ๋๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฑ์์ก๋์ง ์๋์ผ๋ก ๊ฒ์ฆํ ๋ ์ฌ์ฉํด์.
5. ๊ฐ์ฒด ๋ณต์ฌ ๐
๊น์ ๋ณต์ฌ(deep copy)๊ฐ ํ์ํ ๋ Mirror๋ก ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์ํํ๋ฉฐ ๋ณต์ฌํ ์ ์์ด์.
๐ ์ค๋ฌด ์์ : ์๋ ๋ก๊ฑฐ
class AutoLogger {
static func log(_ object: Any, event: String) {
let mirror = Mirror(reflecting: object)
let typeName = "\(mirror.subjectType)"
var logMessage = """
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ ์ด๋ฒคํธ: \(event)
๐ท๏ธ ํ์
: \(typeName)
โฐ ์๊ฐ: \(Date())
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
"""
for child in mirror.children {
if let label = child.label {
logMessage += "\n โข \(label): \(child.value)"
}
}
logMessage += "\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
print(logMessage)
}
}
// ์ฌ์ฉ ์์
struct OrderPlaced {
let orderId: String
let userId: String
let totalAmount: Double
let items: [String]
let timestamp: Date
}
let order = OrderPlaced(
orderId: "ORD-2024-001",
userId: "USER-123",
totalAmount: 89000,
items: ["๋งฅ๋ถ ์ผ์ด์ค", "๋ฌด์ ๋ง์ฐ์ค"],
timestamp: Date()
)
AutoLogger.log(order, event: "์ฃผ๋ฌธ ์๋ฃ")
// ์ถ๋ ฅ:
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ ์ด๋ฒคํธ: ์ฃผ๋ฌธ ์๋ฃ
// ๐ท๏ธ ํ์
: OrderPlaced
// โฐ ์๊ฐ: 2024-01-15 14:30:00 +0000
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// โข orderId: ORD-2024-001
// โข userId: USER-123
// โข totalAmount: 89000.0
// โข items: ["๋งฅ๋ถ ์ผ์ด์ค", "๋ฌด์ ๋ง์ฐ์ค"]
// โข timestamp: 2024-01-15 14:30:00 +0000
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Mirror vs ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค
๋ฐํ์ ํ์ ๊ฒ์ฌ๋ฅผ ํ๋ ๋ฐฉ๋ฒ์ Mirror๋ง ์๋ ๊ฒ ์๋์์. ๋ค๋ฅธ ๋ฐฉ๋ฒ๋ค๊ณผ ๋น๊ตํด๋ณผ๊น์?
| ๋ฐฉ๋ฒ | ์ฅ์ | ๋จ์ | ์ฌ์ฉ ์๊ธฐ |
|---|---|---|---|
Mirror |
ํ๋กํผํฐ ์ํ ๊ฐ๋ฅ ๊ตฌ์กฐ ํ์ ๊ฐ๋ฅ |
์ฑ๋ฅ ์ค๋ฒํค๋ ์ฝ๊ธฐ ์ ์ฉ |
๋๋ฒ๊น
, ๋ก๊น
๊ฐ์ฒด ๊ฒ์ฌ |
type(of:) |
๋น ๋ฆ ๊ฐ๋จํจ |
ํ์
๋ง ํ์ธ ๊ฐ๋ฅ ๋ด๋ถ ๊ตฌ์กฐ ๋ชจ๋ฆ |
ํ์ ์ฒดํฌ๋ง ํ์ํ ๋ |
is / as? |
ํ์
์บ์คํ
๋์ ๊ฐ๋ฅ ์์ ํจ |
ํน์ ํ์
๋ง ํ์ธ ํ๋กํผํฐ ์ ๊ทผ ๋ถ๊ฐ |
ํ์ ๋ณํ์ด ํ์ํ ๋ |
Codable |
์ง๋ ฌํ/์ญ์ง๋ ฌํ ํ์ ์์ |
ํ๋กํ ์ฝ ์ฑํ ํ์ ์ ํ์ |
JSON ๋ณํ |
๐ ๊ฐ ๋ฐฉ๋ฒ์ ์ฌ์ฉ ์์
struct Person {
let name: String
let age: Int
}
let person = Person(name: "๊น์ฒ ์", age: 28)
// 1. Mirror - ํ๋กํผํฐ ์ํ
let mirror = Mirror(reflecting: person)
print("Mirror๋ก ํ์ธ:")
for child in mirror.children {
if let label = child.label {
print(" \(label): \(child.value)")
}
}
// 2. type(of:) - ํ์
๋ง ํ์ธ
let personType = type(of: person)
print("\ntype(of:)๋ก ํ์ธ: \(personType)") // Person
// 3. is - ํ์
์ฒดํฌ
let isPersonType = person is Person
print("\nis๋ก ํ์ธ: \(isPersonType)") // true
// 4. as? - ํ์
์บ์คํ
let anyValue: Any = person
if let castedPerson = anyValue as? Person {
print("\nas?๋ก ํ์ธ: \(castedPerson.name)") // ๊น์ฒ ์
}
// ์ฑ๋ฅ ๋น๊ต (๋๋ต์ ์ธ ์๋)
// type(of:) > is/as? > Mirror
// Mirror๋ ๊ฐ์ฅ ๋๋ฆฌ์ง๋ง ๊ฐ์ฅ ๋ง์ ์ ๋ณด๋ฅผ ์ ๊ณต
๐ก ๋ฒ ์คํธ ํ๋ํฐ์ค
โจ Mirror๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๋ ํ
1. ๊ฐ๋ฐ/๋๋ฒ๊ทธ ํ๊ฒฝ์์๋ง ์ฌ์ฉ
ํ๋ก๋์
์ฝ๋์ ํต์ฌ ๋ก์ง์๋ Mirror ์ฌ์ฉ์ ์์ ํ๊ณ , ๋๋ฒ๊น
์ด๋ ๋ก๊น
์ฉ๋๋ก๋ง ์ฌ์ฉํ์ธ์.
2. ์บ์ฑ ํ์ฉ
๊ฐ์ ํ์
์ Mirror๋ฅผ ๋ฐ๋ณตํด์ ์์ฑํ์ง ๋ง๊ณ , ๊ฐ๋ฅํ๋ฉด ์บ์ฑํด์ ์ฌ์ฌ์ฉํ์ธ์.
3. ํ์
์ฒดํฌ ๋จผ์
Mirror๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ type(of:)๋ is๋ก ๋จผ์ ํ์
์ ํ์ธํ๋ ๊ฒ ํจ์จ์ ์ด์์.
4. ์ต์
๋ ์ฒ๋ฆฌ ์ฒ ์ ํ
child.label์ ํญ์ ์ต์
๋์ด๋ ์์ ํ๊ฒ ์ฒ๋ฆฌํ์ธ์.
5. CustomReflectable ํ์ฉ
๋ฏผ๊ฐํ ์ ๋ณด๊ฐ ์๋ ํ์
์ CustomReflectable์ ๊ตฌํํด์ ๋
ธ์ถ์ ์ ์ดํ์ธ์.
๐ฏ ์ฑ๋ฅ ์ต์ ํ ์์
// โ ๋์ ์: ๋ฐ๋ณต๋ฌธ ์์์ Mirror ์์ฑ
func processItems(_ items: [Person]) {
for item in items {
let mirror = Mirror(reflecting: item) // ๋งค๋ฒ ์์ฑ!
// ... ์ฒ๋ฆฌ ...
}
}
// โ
์ข์ ์: ํ์
๋ณ๋ก ํ ๋ฒ๋ง ์์ฑ
class MirrorCache {
private var cache: [String: Mirror] = [:]
func getMirror(for object: Any) -> Mirror {
let typeName = "\(type(of: object))"
if let cached = cache[typeName] {
return cached
}
let mirror = Mirror(reflecting: object)
cache[typeName] = mirror
return mirror
}
}
let cache = MirrorCache()
func processItemsOptimized(_ items: [Person]) {
for item in items {
let mirror = cache.getMirror(for: item)
// ... ์ฒ๋ฆฌ ...
}
}
๐ ์ฌ๋ฅ๋ท์์ ๋ ๋ฐฐ์ฐ๊ธฐ
Swift์ ๋ฆฌํ๋ ์
๊ณผ Mirror๋ ์ ๋ง ๊น์ด ์๋ ์ฃผ์ ์์. ์ด ๊ธ์์ ๋ค๋ฃฌ ๋ด์ฉ์ ์์์ ๋ถ๊ณผํ๋ต๋๋ค! ๐
๋ ๊ณ ๊ธ ๊ธฐ๋ฒ์ด๋ ์ค๋ฌด ํ์ฉ ์ฌ๋ก๊ฐ ๊ถ๊ธํ๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ Swift ์ ๋ฌธ๊ฐ๋ค์ ๊ฐ์๋ ๋ฉํ ๋ง์ ๋ฐ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์์. ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง, ์ด๋ค ํจ์ ์ ์กฐ์ฌํด์ผ ํ๋์ง ๋ฑ ์ค์ ๊ฒฝํ์ ๊ณต์ ๋ฐ์ ์ ์๊ฑฐ๋ ์!
๐ ํ์ต ๋ก๋๋งต ์ ์
์ด๊ธ ๐ฑ
โข Mirror ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ ์ตํ๊ธฐ
โข children ํ๋กํผํฐ๋ก ํ๋กํผํฐ ์ํํ๊ธฐ
โข displayStyle๋ก ํ์
๊ตฌ๋ถํ๊ธฐ
์ค๊ธ ๐ฟ
โข CustomReflectable ํ๋กํ ์ฝ ๊ตฌํ
โข ์ฌ๊ท์ ๊ฐ์ฒด ํ์
โข ์์ ๊ตฌ์กฐ ํ์
โข ์ค์ฉ์ ์ธ ์ ํธ๋ฆฌํฐ ํจ์ ๋ง๋ค๊ธฐ
๊ณ ๊ธ ๐ณ
โข ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
โข ์ปค์คํ
์ง๋ ฌํ ์์คํ
๊ตฌ์ถ
โข ๋ฉํํ๋ก๊ทธ๋๋ฐ ํจํด
โข ํ๋ ์์ํฌ ๊ฐ๋ฐ์ ํ์ฉ
๐ฌ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์ค๋์ Swift์ ๋ฆฌํ๋ ์
๊ณผ Mirror์ ๋ํด ์์๋ดค์ด์! ๐
์ฒ์์๋ ์ข ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ง๋ง, ํ ๋ฒ ์ต์ํด์ง๋ฉด ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ๊ฐ ๋๋ต๋๋ค. ํนํ ๋๋ฒ๊น
ํ ๋๋ ๋ณต์กํ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ ๋ค๋ฃฐ ๋ Mirror๋งํผ ์ ์ฉํ ๊ฒ ์์ด์.
ํ์ง๋ง ๊ธฐ์ตํ์ธ์! ๐ฏ Mirror๋ "ํ์ํ ๋" ์ฌ์ฉํ๋ ๋๊ตฌ์์. ๋ชจ๋ ๊ณณ์ ๋จ์ฉํ๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ผ๋, ์ ์ฌ์ ์์ ํ์ฉํ๋ ๊ฒ ์ค์ํด์.
์ฌ๋ฌ๋ถ์ Swift ๊ฐ๋ฐ ์ฌ์ ์ ์ด ๊ธ์ด ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ์ด์. ๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์ธ์ ๋ ๋๊ธ๋ก ๋ฌผ์ด๋ด ์ฃผ์ธ์! ๐
๊ทธ๋ผ ๋ค์์ ๋ ์ฌ๋ฏธ์๋ Swift ์ด์ผ๊ธฐ๋ก ๋ง๋์! ํดํผ ์ฝ๋ฉ! ๐ปโจ
๐ ์ด ๊ธ์ด ๋์์ด ๋์
จ๋์?
๋ ๋ง์ Swift ์ง์์ ์ํ์ ๋ค๋ฉด ์ฌ๋ฅ๋ท์ '์ง์์ธ์ ์ฒ'์ ๋ฐฉ๋ฌธํด๋ณด์ธ์!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.