오늘 배운 내용
class VS struct
struct 는 값 타입이다.
이것은 struct의 인스턴스를 다른 변수에 할당하거나 함수에 전달할 때, 해당 인스턴스의 복사본이 생성되고 전달된다는 것을 의미한다.
myStruct1을 myStruct2에 할당한 후 myStruct2의 name을 변경하면, myStruct1의 name은 변경되지 않는다. 이는 두 구조체 인스턴스가 서로 독립적인 복사본이기 때문이다.
class 는 참조 타입이다. 클래스의 인스턴스를 다른 변수에 할당하거나 함수에 전달할 때, 인스턴스 자체가 아닌 그 인스턴스를 가리키는 참조가 전달된다.
myClass1을 myClass2에 할당한 후 myClass2의 name을 변경하면, myClass1의 name도 변경된다. 이는 myClass1과 myClass2가 동일한 인스턴스를 가리키기 때문이다.
class 는 상속을 지원한다. 다른 클래스 로부터 속성과 메소드를 상속받아 사용 가능하다.
struct 는 상속을 지원하지 않는다. 그러나 프로토콜을 통해 유사하게 사용 가능하다.
다음은 클래스와 구조체의 차이에 대한 자세한 부가 설명이다.
클래스: 클래스 인스턴스는 deinit을 사용하여 할당 해제될 때 정리할 수 있는 코드를 실행할 수 있습니다.
구조체: 구조체에는 할당 해제 시점에 호출되는 deinit 메소드가 없습니다.
클래스: 클래스 인스턴스는 실행 시간에 타입을 검사하고 해석하기 위해 타입 캐스팅을 사용할 수 있습니다. 이는 인스턴스가 그것의 클래스나 슈퍼클래스 중 하나의 인스턴스인지 확인하는데 유용합니다.
구조체: 구조체는 타입 캐스팅을 지원하지 않습니다.
클래스: 복잡한 객체 모델을 구현할 때, 상속을 통해 코드 재사용성이 필요할 때, 또는 애플리케이션 내에서 인스턴스의 상태를 여러 곳에서 공유해야 할 때 사용됩니다.
구조체: 비교적 작고, 단순한 데이터 값을 캡슐화할 때 주로 사용됩니다. Swift의 많은 기본 타입들(예: Int, String, Array)은 실제로 구조체로 구현되어 있습니다.
Swift는 구조체 사용을 선호하며, Apple은 클래스보다 구조체를 사용하도록 권장합니다.
이는 구조체가 더 예측 가능하고, 관리하기 쉬운 코드를 만드는데 도움이 되기 때문입니다. 그러나 상속이 필요하거나, 데이터를 여러 곳에서 공유해야 할 때는 클래스가 더 적합할 수 있습니다.
struct SampleStruct {
var name: String
init(name: String) {
self.name = name
}
func buildHelloMsg() {
"Hello " + name
}
}
class SampleClass {
var name: String
init(name: String) {
self.name = name
}
func buildHelloMsg() {
"Hello " + name
}
}
let myStruct1 = SampleStruct(name: "Mark")
var myStruct2 = myStruct1
myStruct2.name = "David"
print(myStruct1.name)
print(myStruct2.name)
let myClass1 = SampleClass(name: "Mark")
var myClass2 = myClass1
myClass2.name = "David"
print(myClass1.name)
print(myClass2.name)
property wrapper
Swift의 Property Wrapper는 속성에 저장되는 값에 대한 관리를 캡슐화하고 재사용하기 위한 강력한 도구입니다. 이를 통해 값의 검증, 변형, 저장 방식 등을 커스터마이즈할 수 있으며, 이러한 로직을 속성 선언에 직접 적용하지 않고도 사용할 수 있습니다. Property Wrapper는 @propertyWrapper 키워드로 정의됩니다.
Property Wrapper의 주요 기능:
값의 저장: Property Wrapper는 속성에 할당된 값의 저장 방식을 커스터마이즈할 수 있게 해줍니다.
값의 변형과 검증: 할당되기 전이나 조회되기 전에 값을 변형하거나 검증할 수 있습니다.
코드 재사용성과 관심사의 분리: 공통적인 속성 관리 코드를 여러 속성에 재사용할 수 있습니다.
@propertyWrapper
struct MinMaxVal<V: Comparable> {
var value: V
let min: V
let max: V
init(wrappedValue: V, min: V, max: V) {
value = wrappedValue
self.min = min
self.max = max
}
var wrappedValue: V {
get { return value }
set {
if newValue > max {
value = max
} else if newValue < min {
value = min
} else {
value = newValue
}
}
}
}
struct Demo {
@MinMaxVal(min: 10, max:150) var value: Int = 100
@MinMaxVal(min: "Apple", max: "Orange") var value2: String = ""
}
var demo = Demo()
demo.value2 = "Banana"
print(demo.value2)
demo.value2 = "Pear"
print(demo.value2)
오늘의 실습 프로젝트
- class (init, super init 사용)
- 클래스를 초기화할 때, 부모 클래스에서 받은 프로퍼티는 super init 으로 초기화 한다
- 부모 클래스를 상속하여 하위 클래스를 여러 개 만들고, 데이터의 타입을 부모 클래스 타입으로 하면, 하위 클래스 모두 호환 가능
- Section - header
- swiftUI 에서 Section(header: Text("Electric Cars")) 와 같이, view 에서 분류 가능
- 이어서, ForEach(cars.filter { $0 is ElectricCar } 에서, filter 와 같은 메서드를 사용하여 원하는 데이터만 필터링
오늘 푼 문제
- 약수의 합 (프로그래머스)
내 코드
func solution(_ n:Int) -> Int {
guard n != 0 else {
return 0
}
return Array(1...n).filter { n % $0 == 0 }.reduce(0, +)
}
느낀점
오늘은 데이터 모델링 실습을 하면서, 클래스 상속, 재정의를 몸소 학습할 수 있었다. 개념으로만 알고 있던 내용을 실습을 통해 적용하면서 앞으로 이렇게 부지런히 개념을 터득해나가면 되겠다는 생각이 들었다.
무엇보다도 프로토콜 지향 프로그래밍의 매력에 흠뻑 빠져들었다.
프로토콜 익스텐션에 메서드를 추가함으로써, 해당 프로토콜을 준수하는 클래스의 하위 클래스에 모두 적용이 가능하다! 이를 통해 클린 아키텍쳐를 구현할 수 있다!