Mirror.handleChildren()
recursive reflections: inspect/manipulate on children's children.
๐พ ็จๅผ๏ผ replit
// *: 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)
}
}
}
}
โฌ๏ธ ้่ฆ๏ผ Logger
// 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.")
}
}
ๅท่ก็ตๆ๏ผ
// โโโโโโโโโโโโโโโโโโโโโโโโโโโ
// โ # 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.\
Pattern Matching - pattern-match on mirror's children.
for case let ... where - (pattern matching + binding + condition)
if let ... as? - optional binding.
(... as? ...)?.method() - optional chaining.
... as! ... - force type casting.
Logger is used in [๐็ฏไพ].
History
(2022.01.27) - first version. (global function)
้ๅ็จๅผ็ขผๆ่ฉฒ่ฆๅฏซๆ global function๏ผๅฆๆๅฏซๆ protocol method ๆๅบ็พ่จฑๅคๅ้ก (ไพๅฆ๏ผchildren of children ๅฏ่ฝๆ นๆฌไธ้ตๅพช้ๅ protocol๏ผๅฐ่ด็กๆณไฝฟ็จๆญค method recursively)
๐ ๐พ ็จๅผ๏ผ attemp 1 (with lots of errors)
/// โญ 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)
}
}
}
Last updated