SwiftUI๋ฅผ ๋ณด๋ฉด
body์ some ํค์๋๊ฐ ๋ถ์๊ฑธ ๋ณผ ์ ์์ต๋๋ค.
์ด๊ฒ ๋ญ์ง ๊ถ๊ธํด์ ธ์ ์ฐพ์๋ณด๊ณ ์ ๋ฆฌํ๊ณ ์ ํฉ๋๋ค ๐ค
์ฐธ๊ณ ์๋ฃ : https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html
https://jcsoohwancho.github.io/2019-08-24-Opaque-Type-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0/
Opaque type
๋ฆฌํด๋๋ ๊ฐ์ ํ์
์ ๋ณด๋ฅผ ์จ๊ธฐ๊ณ ์ ํฉ๋๋ค. ์ฆ ํจ์๊ฐ ๋ฉ์๋๊ฐ ๋ฆฌํดํ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ ์ ๊ณตํ๋ ๋์ ์ ๋ฆฌํด๊ฐ์ ํด๋น ํ์
์ด ์ฑํํ๊ณ ์๋ ํ๋กํ ์ฝ ์ธก๋ฉด์์ ์ค๋ช
๋ฉ๋๋ค.
Opaque type์ ์ค์ ํ์
์ ๋ณด๋ฅผ ๊ฐ์ถ์ด ๋ชจ๋๊ณผ ๋ชจ๋์ ๊ฒฐํฉ์ฑ์ ๋ฎ์ถ๋๋ฐ ์ ์ฉํ๋ค๊ณ ํฉ๋๋ค.
์์ )
๋ง์ฝ ASCII ๊ทธ๋ฆผ ๋ชจ์์ ๊ทธ๋ฆฌ๋ ๋ชจ๋์ ์์ฑํ๊ณ ์๋ค ํฉ์๋ค.
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result: [String] = []
for length in 1...size {
result.append(String(repeating: "*", count: length))
}
return result.joined(separator: "\n")
}
}
let smallTriangle = Triangle(size: 3)
print(smallTriangle.draw())
// *
// **
// ***
ํ๋กํ ์ฝ Shape์ ์ค์ํ๋ Triangle์ ์์ ์ฝ๋์ ๊ฐ์ต๋๋ค.
์ด๋ฒ์ ๋ชจ์์ ์์ง์ผ๋ก ๋ค์ง๋ FippledShape๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\n")
return lines.reversed().joined(separator: "\n")
}
}
let flippedTriangle = FlippedShape(shape: smallTriangle)
print(flippedTriangle.draw())
// ***
// **
// *
ํ์ง๋ง ์ฌ๊ธฐ์๋ ์ ์ฝ์ฌํญ์ด ์๋๋ฐ์. FlippedShape์ ๋ณด๋ฉด <T: Shape>์ ๊ฐ์ด ์ ๋ค๋ฆญ ํ์
์ด ๋
ธ์ถ๋ฉ๋๋ค.
์ฌ๊ธฐ์ ๋ ํ๋๋ฅผ ๋ ๊ฐ์ผ๋ค๋ฉด ?
struct JoinedShape<T: Shape, U: Shape>: Shape {
var top: T
var bottom: U
func draw() -> String {
return top.draw() + "\n" + bottom.draw()
}
}
let joinedTriangles = JoinedShape(top: smallTriangle, bottom: flippedTriangle)
print(joinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
JoinedShape<FlippedShape<Triangle>, Triangle> ์ ๊ฐ์ด ํ์
์ด ์ค์ฒฉ๋๊ณ ๋ถํ์ํ ์ฝ๋๊ฐ ๊ณ์ ์์ฑ๋ฉ๋๋ค.
Shape ํ๋กํ ์ฝ์ ์์ฑ์ ๋ํ ๊ตฌ์ฒด์ ์ธ ์ ๋ณด ๋
ธ์ถ์ ์ ์ฒด ๋ฐํ ํ์
์ ๋ช
์ํด์ผ ํ๊ธฐ ๋๋ฌธ์ ASCII ๊ทธ๋ฆผ ๋ชจ๋์ ์ธํฐํ์ด์ค ์ผ๋ถ๊ฐ ์๋ ์ ์ฒด ํ์
์ด ๋
ธ์ถ ๋ ์ ์์ต๋๋ค.
JoinedShape ๋ฐ FlippedShape์ ๊ฐ์ Wrapper ํ์
์ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ์ค์ํ์ง ์์ผ๋ฉฐ ํ์๋์ง ์์์ผ ํฉ๋๋ค.
ํด๋น ๊ตฌ์กฐ์ฒด๋ค์ด ๋ชจ๋ Shape ํ๋กํ ์ฝ์ ์ฑํํ๊ณ ์๋ค๋ ์ ์์ ํ์
์ ๋
ธ์ถ์ ๊ฐ์ถ๊ณ ๋ชจ๋์ ์ธํฐํ์ด์ค์์๋ Shape์์ ์๋ ค์ค ํ์๊ฐ ์์ต๋๋ค.
Returning an Opaque Type
Opaque Type์ Generic Type์ ์ญ์ผ๋ก ์๊ฐํ ์ ์์ต๋๋ค. Generic Type์ ์ฌ์ฉํ๋ฉด ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋์์ ํด๋น ํจ์์ ๋งค๊ฐ๋ณ์์ ๋ํ ํ์ ์ ์ ํํ๊ณ ํจ์ ๊ตฌํ์์ ์ถ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ฐ์ ๋ฐํํฉ๋๋ค.
func max<T>(_ x: T, _ y: T) -> T where T: Comparable { … }
์ด๋ฌํ ์ญํ ์ Opaque๋ฅผ ๋ฆฌํด ํ์
์ผ๋ก ๊ฐ์ง๋ ํจ์์๋ ์ ๋ฐ๋์
๋๋ค. Opaque Type ์ฌ์ฉํ๋ฉด ํจ์ ๊ตฌํ์ด ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋์์ ์ถ์ํ๋ ๋ฐฉ์์ผ๋ก ๋ฐํํ๋ ๊ฐ์ ์ ํ์ ์ ํํ ์ ์์ต๋๋ค.
generic type : ํธ์ถ ํ๋ ์ชฝ (๊ตฌ์ฒด์ ์ธ ํ์ ์ง์ ) <-> ํธ์ถ ๋ฐ๋ ์ชฝ(generic์ ์ฌ์ฉํ ์ถ์ํ)
opaque tyoe: ํธ์ถ ํ๋ ์ชฝ (๋ชจ๋๊ฐ ๊ฒฐํฉ์ ์ค์ด๊ธฐ ์ํ ์ถ์ํ) <-> ํธ์ถ ๋ฐ๋ ์ชฝ(ํน์ ์ธํฐํ์ด์ค๋ก ํตํฉ๋๋ค๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ง์ )
struct Square: Shape {
var size: Int
func draw() -> String {
let line = String(repeating: "*", count: size)
let result = Array<String>(repeating: line, count: size)
return result.joined(separator: "\n")
}
}
func makeTrapezoid() -> some Shape {
let top = Triangle(size: 2)
let middle = Square(size: 2)
let bottom = FlippedShape(shape: top)
let trapezoid = JoinedShape(
top: top,
bottom: JoinedShape(top: middle, bottom: bottom)
)
return trapezoid
}
let trapezoid = makeTrapezoid()
print(trapezoid.draw())
// *
// **
// **
// **
// **
// *
makeTrapezoid() ํจ์๋ some Shape์ ๋ฆฌํด ํ์ ์ผ๋ก ๊ฐ์ง๋๋ค. ๋ฐ๋ผ์ ํจ์๋ Shape ํ๋กํ ์ฝ์ ์ฑํํ๋ ์ด๋ค ๊ฐ์ ๋ฐํํฉ๋๋ค. ๊ตฌ์ฒด์ ์ธ type์ ๋ช ์ํ์ง ์๊ณ ์ธํฐํ์ด์ค์ ๊ทผ๋ณธ์ ์ธ ๋ถ๋ถ๋ง์ ํํํฉ๋๋ค. ์ฆ ๋ฆฌํด ๊ฐ shape๊ฐ ๊ทธ ์ธํฐํ์ด์ค์์ ๋ง๋ค์ด์ก๋๋ฐ ์ด๋ค ํ์ ์ผ๋ก ๋ง๋ค์ด์ก๋์ง ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๋๋ฌ๋ด์ง ์์์ฑ shape๋ฅผ ๋ฆฌํดํฉ๋๋ค.
func flip<T: Shape>(_ shape: T) -> some Shape {
return FlippedShape(shape: shape)
}
func join<T: Shape, U: Shape>(_ top: T, _ bottom: U) -> some Shape {
JoinedShape(top: top, bottom: bottom)
}
let opaqueJoinedTriangles = join(smallTriangle, flip(smallTriangle))
print(opaqueJoinedTriangles.draw())
// *
// **
// ***
// ***
// **
// *
generic๊ณผ opaque๋ฅผ ๊ฒฐํฉํ์ฌ ์ฌ์ฉ ํ ์๋ ์์ต๋๋ค. flip(), join() ํจ์๊ฐ Shape๋ฅผ ์ฑํํ๋ ์ด๋ค ํ์ ์ ๋ฐํํจ์ผ๋ก์จ ํ์ ์ด ๊ฐ์ํ๋๋ ๊ฒ์ ๋ง์ ์ ์์ต๋๋ค.
Opaque Type๊ณผ Protocol Type์ ์ฐจ์ด์
opaque type์ ๋ฆฌํดํ๋ ๊ฒ๊ณผ protocol type์ ๋ฆฌํด ํ์
์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๋งค์ฐ ๋น์ทํด๋ณด์
๋๋ค.
ํ์ง๋ง type identity๋ฅผ ๋ณด์กดํ๋์ง ์๋์ง์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค.
opaque type์ ๋น๋ก ํจ์์ ํธ์ถ์๊ฐ ์ด๋ค ํ์
์ธ์ง ๋ณผ์ ์์ด๋, ํ๋์ ๊ตฌ์ฒด์ ์ธ ํ์
์ ๋ํ๋
๋๋ค. ๋ฐ๋ฉด protocol type์ protocol์ ์์ํ๋ ์ด๋ค ํ์
์ ๋ํ๋
๋๋ค.
์ผ๋ฐ์ ์ผ๋ก, protocol type์ด opaque type๋ณด๋ค ๋ ์ ์ฐํจ์ ์ ๊ณตํฉ๋๋ค. opaque type์ ํ์
์ ๋ํด ๊ฐ๋ ฅํ ๋ณด์ฅ์ ์ ๊ณตํฉ๋๋ค.
์๋ฅผ ๋ค์ด๋ด
์๋ค.
func protoFlip<T: Shape>(_ shape: T) -> Shape {
return FlippedShape(shape: shape)
}
Shape๋ผ๋ protocol type์ ๋ฆฌํดํ๋ protoFlip ํจ์๊ฐ ์์ต๋๋ค.
flip() ํจ์์ ๋ฌ๋ฆฌ protoFlip() ํจ์๋ Shape ํ๋กํ ์ฝ์ ์์ํ๊ณ ์์๋ฟ, ํญ์ ๊ฐ์ ํ์
์ ํ์๋ก ํ์ง ์์ต๋๋ค. ์ฆ, ์ฌ๋ฌ ํ์
์ ๋ฐํ ํ ์ ์๋ ์ ๋์ฑ์ ๊ฐ์ง๋๋ค.
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
๋ง์ฝ protoFlip ํจ์๊ฐ ์์ ๊ฐ์ด ์์ ๋์๋ค๋ฉด, Square ๊ฐ์ฒด ๋๋ FlippedShape ๊ฐ์ฒด๋ฅผ ๋ฐํ ํ ๊ฒ์
๋๋ค. ์ฆ protoFlip()์ ๋ช
ํํ์ง ์์ ๋ฐํ๊ฐ์ ํ์
์ ์์กดํ๋ ๋ง์ ๊ณณ์์ ์ฌ์ฉํ ์ ์์์ ์๋ฏธํฉ๋๋ค.
์๋ฅผ ๋ค์ด == ์ฐ์ฐ์๋ฅผ ์ฐ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ ๊ฒ์
๋๋ค. (๊ตฌ์ฒด์ ์ธ ํ์
์ ๊ฐ์ง์ง ์์ผ๋ฏ๋ก !)
let protoFlippedTriangle = protoFlip(smallTriangle)
let sameThing = protoFlip(smallTriangle)
protoFlippedTriangle == sameThing // Error
๋จผ์ , ์์ชฝ ํ์
์ ๋ํ ๊ตฌ์ฒด์ ์ธ ํ์
์ ๋ณด์ฅํ ์ ์์ผ๋ฉฐ ํ๋กํ ์ฝ์ ์ผ๋ถ ์ธํฐํ์ด์ค๋ง ์ด์ฉํ ์ ์๊ฒ ๋๋ ๋ฌธ์ ๊ฐ ์๊น๋๋ค. Shape์ ==์ ์ฌ์ฉ ํ ์ ์๋๋ก Equatable์ ์ถ๊ฐ๋ก ์ค์ํ๋ค ํ๋๋ผ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ด ์๊ธฐ ๋๋ฌธ์ ์์ ์ ํ์
์ ๋ณด๊ฐ ํ์ํ == ๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
๋๋ค๋ฅธ ๋ฌธ์ ๋ ํ๋กํ ์ฝ๋ก ๋ฐํํ ๊ฐ์ ์ค์ฒฉํด์ ์ฌ์ฉ ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
let flippedTriangle = protoFlip(smallTriangle)
let original = protoFlip(filppedTriangle) // Error!
ํ๋กํ ์ฝ ํ์
์ผ๋ก ๋ฐํํ ๊ฐ์ ํ๋กํ ์ฝ์ ์ฑํํ์ง ์์ ๊ฒ์ผ๋ก ์ฌ๊ฒจ์ง๊ธฐ ๋๋ฌธ์
๋๋ค.
๊ฒฐ๊ตญ protocol type์ ๋ช
ํํ ํ์
์ด ์๊ธฐ ๋๋ฌธ์ ~ ๋ก๋ถํฐ ๋ฐ์ํ๋ ์ฌ๋ฌ๊ฐ์ง ์ด์๋ค์ด ์์ต๋๋ค. ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ๋ช
ํํ ํ์
์ด ์๋ opaque type์ ์ด์ฉํฉ๋๋ค.
protocol Container {
associatedtype Item
var count: Int { get }
subscript(i: Int) -> Item { get }
}
extension Array: Container { }
< protocol type >
// Error: Protocol with associated types can't be used as a return type.
func makeProtocolContainer<T>(item: T) -> Container {
return [item]
}
// Error: Not enough information to infer C.
func makeProtocolContainer<T, C: Container>(item: T) -> C {
return [item]
}
ํ๋กํ ์ฝ Container๊ฐ ์ฐ๊ด ํ์ Item์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
any Container๋ฅผ ์ฐ๋ฉด ํด๊ฒฐ๋๋ค๊ตฌ ํ๋ค์ ,,, ํ์ง๋ง ๋ํ๋จผํธ์์ some์ผ๋ก ํด๊ฒฐํ๋๋ฐ ๋์ ์ฐจ์ด๊ฐ ๋ญ์ง๋ ์ข ๋ ์ฐพ์๋ด ์๋ด ...
๋ํ ๋๋ฒ์งธ ํจ์๋ Container๋ฅผ ์ถ๋ก ํ ์ ๋ณด๊ฐ ์๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
<Opaque type ์ฌ์ฉํ์ฌ ํด๊ฒฐ>
func makeOpaqueContainer<T>(item: T) -> some Container {
return [item]
}
let opaqueContainer = makeOpaqueContainer(item: 12)
let twelve = opaqueContainer[0]
print(type(of: twelve))
// Prints "Int"
์ฐ์ generic์ ๋ฐ๋ ๊ฐ๋ ์ด ํ์ํ ๋๋ ์๋ค๋๊ฒ์ ์ฒ์ ๋๊ผ์ต๋๋ค. ๋ชจ๋๊ฐ ๊ฒฐํฉ์ ๋ณต์กํจ์ ์ ๋ฐํ๋ some ํค์๋๋ก ๋ช ํํ ํ์ ์ ๋ณด์ฅํ๋ค๋ ์ ์์ ํ๋กํ ์ฝ๊ณผ ์ ๋ค๋ฆญ์ ์ ์ถฉํ ๊ฐ๋ค๋ ๋๋์ ๋ฐ์์ต๋๋ค. ์ฌ์ฉํด๋ณธ์ ์ด ์์ด ์ ์๋ฟ์ง ์์ผ๋ ๊ฐ๋ ์ ๋ฐ๋ณต์ ์ผ๋ก ์ฝ์ด๋ด์ผ ํ ๊ฑฐ ๊ฐ์ต๋๋ค ํํ ์๋ก์ด ๊ฐ๋ ์ ๋ฐฐ์์ ๋ฐฐ์๋ ๋ฐฐ์๋ ๋ถ์กฑํจ์ด ๋์ด ์๋๊ฑฐ ๊ฐ์ด๋ค ,,, any๋ ํ๋ฒ ์ฐพ์๋ด์ผ๊ฒ ๊ตฐ์ ๊ทธ๋ผ ์ด๋ง ~~
'IOS๐ > iOS+Swift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Swift] Optional์ ๋ํ ๊ณ ์ฐฐ (0) | 2022.04.23 |
---|---|
[Swift] split, components ์ฐจ์ด (with: ์ฑ๋ฅ) (0) | 2022.04.14 |
[iOS] Swift Unit Test ์ดํด๋ณด๊ธฐ (0) | 2022.04.07 |
[Swift] Access Control (open, public, internal, fileprivate, private) (0) | 2022.03.29 |
[Swift] CustomStringConvertible (0) | 2022.03.07 |
๋๊ธ