Cannot assign to property: 'self' is immutable
→ 스유에서는 뷰를 구조체로 구성하기 때문에, 값을 변경하기 위해서는 @State 키워드를 사용한다.
struct User {
var name = "고래밥"
// 값을 수정하기 위해서는 mutating 키워드 필요.
mutating func changeNickName() {
name = "칙촉"
}
var introduce: String {
mutating get {
name = "스파이더맨"
return "안녕하세요 \\(name)입니다. "
}
}
}
joined(separator:)
//Returns a new string by concatenating the elements of the sequence,
//adding the given separator between each element.
//어레이의 각 요소를 separator로 구분해 하나의 스트링으로 리턴
func joined(separator: String = "" ) -> String
import UIKit
protocol Shape {
func draw() -> String
}
struct Triangle: Shape {
var size: Int
func draw() -> String {
var result: [String] = []
for length in 1...size {
let star = String(repeating: "*", count: length)
result.append(star)
}
return result.joined(separator: "\\n")
}
}
var triangle = Triangle(size: 10)
print(triangle.draw())
struct FlippedShape<T: Shape>: Shape {
var shape: T
func draw() -> String {
let lines = shape.draw().split(separator: "\\n")
return lines.reversed().joined(separator: "\\n")
}
}
var flippedTriangle = FlippedShape(shape: triangle)
print(flippedTriangle.draw())
//struct JoinedTriangle<T: Shape>: Shape {
// var top: T
// var bottom: T
//
// func draw() -> String {
// let result = top.draw() + "\\n" + bottom.draw()
// return result
// }
//}
//let joinedTriangle = JoinedTriangle(top: triangle, bottom: flipTriangle)
//제네릭을 사용해 타입을 결정하면, 호출 부에서 타입이 결정되는데 이때, top과 bottom은 다른 타입이기 때문에
//T: shape으로 동시 구성해놓은 JoinedTriangle은 오류가 발생한다
struct JoinedShape<T: Shape, U: Shape>: Shape {
var top: T
var bottom: U
func draw() -> String {
let result = top.draw() + "\\n" + bottom.draw()
return result
}
}
let joinedTriangle = JoinedShape(top: triangle, bottom: flippedTriangle)
print(joinedTriangle.draw())
//함수 호출 부에 타입이 결정된다. -> 타입 유출로 이어짐
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())
struct VerticalShapes: Shape {
var shapes: [any Shape]
func draw() -> String {
return shapes.map { $0.draw() }.joined(separator: "\\n\\n")
}
}
let largeTriangle = Triangle(size: 5)
let largeSquare = Square(size: 5)
let vertical = VerticalShapes(shapes: [largeTriangle, largeSquare])
print(vertical.draw())
Opaque Types과 ****boxed protocol type타입 유출을 방지하면서 얻는 장점
Generic과 Opaque Types 모두 공통적으로 타입에 대한 유연성을 확보할 수 있다. 두 키워드 모두 컴파일 시점에 타입이 결정되지만, Generic의 경우 타입이 선언자 외부로 유출되는 반면 Opaque Types의 경우 타입이 선언자 외부로 유출되지 않는다.
즉, 이를 통해 좀 더 높은 추상화 수준을 확보할 수 있게 된다. 따라서 내부 구현의 변경이 발생해도 특정 프로토콜만 준수할 경우 그 어떠한 인터페이스에 대해서도 대응이 가능해진다.