Mirror, Keypath, DynamicMemberLookUp - Team-HGD/SniffMEET GitHub Wiki
setValue(Any, forKey: String) firebase ... ๊ธฐํ DB ์์ ๋ฑ์์ String์ผ๋ก ํ๋กํผํฐ์ ์ ๊ทผํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ ์๋ค.
๊ทธ๋ผ ํ๋กํผํฐ๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค Constant๋ฅผ ์ถ๊ฐํด์ผ ๋๋๊ฑด๊ฐ? -> ์๊ตฌ ๊ท์ฐฎ๋ค... ์ค์ํ๊ธฐ๋ ๋ฑ ์ข๋ค!
๊ทธ๋์ ์๋ก์ด ๋ฐฉ์์ผ๋ก ํธ์ ๊ธฐ๋ฅ์ ๋ง๋ค์ด๋ณด๋ฉด ์ด๋จ๊น ์ถ์๋ค.
๋ฌผ๋ก Decodable์ ์ฑํํ ๋ค์, json ํ์ผ์ ํตํด property์ ์ด๋ฆ์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, ํ๋กํผํฐ ์ด๋ฆ์ ์ ๊ทผํ ๋๋ง๋ค Decoding์ ํด์ค์ผ ํ๋ค๋ ๋จ์ ์ด ์๋ค.
์ฐ์ ๋์ถฉ setValue ์ ํ์ํ๊ฑด ์์ฑ์ ์ด๋ฆ, ํ์ , ๊ฐ ์ด๋ ๊ฒ ์ธ๊ฐ์ง ์ ๋๊ฒ ๋ค.
๊ทธ๋ผ ๊ฐ๊ฐ์ ์ ๋ณด๋ฅผ ์ด๋ป๊ฒ ์ ์ ์์๊น?
์ฒซ๋ฒ์งธ๋ก ์์ฑ์ ์ด๋ฆ์ ์๊ธฐ ์ํด์ ์ฐ๋ ์น๊ตฌ๋ค.
substructure๊ณผ display style์ ํํํ๋ค.
์ฌ๋ฐ๊ฒ๋ Mirror๋ฅผ ์ฐ๋ฉด private ์์ฑ์๋ ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋ค. ํ์ง๋ง, ์ ์ฐ๋ ๊ฒ ๋น๊ทผ ์ข๋ค.
[[iOS - swift] private ํ๋กํผํฐ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ (#Mirror, private var, private let ํ๋กํผํฐ ์ ๊ทผ)](https://ios-development.tistory.com/1523)
์ด๊ฑฐํ์ธ์ง, ๊ตฌ์กฐ์ฒด์ธ์ง ํ๋จ๋ ๊ฐ๋ฅํ๋ค. pointcofree์์๋ ์ด ๊ธฐ๋ฅ์ผ๋ก ์ฌ๋ฐ๋ ์น๊ตฌ๋ฅผ ๋ง๋ค๊ธฐ๋ ํ๋ค.
Keypath๋ฅผ ํตํด ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋ค.
Keypath<RootType, PropertyType> ๊ฐ ๊ธฐ๋ณธ์ ์ธ ๋ฌธ๋ฒ์ด๋ค.
์์๋ฅผ ๋ค๋ฉด
struct Member {
let name: String
let age: Int
}
let member = Member(name: "ํ๊ฑฐ๋ฉ", age: 10)
let keypath: Keypath<Member, String> = \.name
member[keyPath: \Member.name] // ํ๊ฑฐ๋ฉ
member[keyPath: \.age] // 10 ๋์ ๋ฉค๋ฒ ์ ๊ทผ์ด๋ผ๋ ์น๊ตฌ์ธ๋ฐ, ๋ง์ด ์ฌ์ฉํ์ง ์๋ ์น๊ตฌ์ด์ง๋ง ๋ฐํ์์ ์ด๋ค ์ด๋ฆ์ ๋ฉค๋ฒ๊ฐ ์กด์ฌํ๋์ง ํ๋จํ๋ ์ฉ๋๋ก ์ฌ์ฉํ ์ ์๋ค.
์์๋ฅผ ๋ค๋ฉด ์๋์ ๊ฐ์ด ์ฌ์ฉํด๋ณผ ์ ์๋ค.
@dynamicMemberLookup
struct Book {
subscript(dynamicMember member: String) -> String {
return member
}
}
let book: Book = .init()
book.์ฐ์ // ์ฐ์
book.ํ // ํ ๋ณดํต ๋์ ๋๋ฆฌ์ ์กฐํฉ์ด ๊ด์ฐฎ๊ธฐ๋ ํ๊ณ ๋ง์ด ์ฌ์ฉํ๋ค. ์๋์ฒ๋ผ ํ์ฉํ ์ ์๋ค.
@dynamicMemberLookup
struct Cache {
private var map: [String: String] = ["์ฐ์" : "wowa"]
subscript(dynamicMember member: String) -> String {
return map[member]!
}
}
let book: Book = .init()
book.์ฐ์ // "wowa"์์ ์๋ member๋ก ์ ๊ทผํ ์ ์๋ ํ์ ์ด String์ผ๋ก ํ์ ๋์๋๋ฐ (Swift 4)
์ต๊ทผ๋ถํฐ Keypath๋ฅผ ํตํ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ก๋ค๊ณ ํ๋ค. (Swift 5.1)
์ด ํฌ์คํธ์์ ๋ชฉ์ ๋ฌ์ฑ์ ๋ชปํ๋๋ฐ, ์ฌ์ค ์ด ์น๊ตฌ๋ฅผ ๋์ ํ๊ณ ์ถ์๋ ์ด์ ๋ Keypath๋ฅผ ํตํ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ก๊ธฐ ๋๋ฌธ์ด์๋ค.
๊ฒฐ๊ณผ ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
@dynamicMemberLookup
struct Proxy<T> {
private let wrappedValue: T
private var mapping: [String: Property] = [:]
var allProperties: [Property] {
Array(mapping.values)
}
init(wrappedValue: T) {
self.wrappedValue = wrappedValue
Mirror(reflecting: wrappedValue).children
.compactMap {
guard let label = $0.label else { return nil }
return (label, Property(name: label,
type: type(of: $0.value),
value: $0.value))
}
.forEach{ key, value in
mapping[key] = value
}
}
subscript(dynamicMember member: String) -> Property? {
mapping[member]
}
}์ฐ๋ฆฌ ํ๋ก์ ํธ์์ Proxy๋ฅผ ์ ์ฉํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค์ด๋ณผ ์ ์๋ค.
let dog: Dog = Dog(name: "ํ์ถ์ถ", size: .superSmall, keyword: [.energetic])
let managedObject = NSManagedObject(entity: dogEntity, insertInto: context)
managedObject.setValue(dog.keyword.map{ $0.rawValue }, forKey: "keyword")
managedObject.setValue(dog.name, forKey: "name")
managedObject.setValue(dog.size.rawValue, forKey: "size")let dogProxy: Proxy<Dog> = .init(wrappedValue: dog)
dogProxy.allProperties {
managedObject.setValue($0.value, forKey: $0.name)
}๋ฐ๋ผ์ ์ ๋ค๋ฆญ์ผ๋ก๋ ํํ์ด ๊ฐ๋ฅํ๋ค.
let proxy: Proxy<T> = .init(wrappedValue: T.init())
proxy.allProperties {
managedObject.setValue($0.value, forKey: $0.name)
}๋ฌธ์ ๊ฐ ํ๋ ์๋ค๋ฉด CoreData์ ๋ค์ด๊ฐ ์ ์๋ ๋ฐ์ดํฐ ํ์ ์ proxy์ ๋งค์น์์ผ์ฃผ์ด์ผ ํ๋ค๋ ์ ์ด๋ค.
์ฅ์ : ํ๋กํผํฐ๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ์์ ์ถ๊ฐํ ํ์ ์์. ๊ด๋ฆฌ์ ํธ์์ฑ
๋จ์ : ๋ฐํ์์ ๊ฒฐ์ ๋๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ด์๊ฐ ์์ ์ ์๋ค.
๋ ํด๋ณผ๊ฑฐ๋ฆฌ
๋์ Keypath ๊ตฌ์ฑํ๊ธฐ
์ฌ์ค ์ด๊ฒ ์๋ฏธ๊ฐ ์์ผ๋ ค๋ฉด String ํ์ ์ผ๋ก dynamicMember๋ฅผ ๊ตฌ์ฑํ๋ฉด ์ ๋๋ค.
๋์ Keypath๋ฅผ ์์ฑํ๊ณ keypath๋ฅผ ํตํด ์์ฑ์ ์ ๊ทผํ ์ ์๋๋ก ๋ง๋ค์ด์ผ ํ๋๋ฐ, (ํ์ ์์ ์ฑ ๋๋ฌธ)
๋์ Keypath๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ Swift ์์ ์ ๊ณตํ๊ณ ์์ง ์์์ ์ฐํ ๋ฐฉ๋ฒ์ ์ฐพ๋ ์คโฆ ์ข์ ์์ด๋์ด ๋ฐ์ต๋๋ค.