TIL은 편한 말투로 작성됩니다~
오늘은 "Struct와 Class / 프로토콜"을 공부했다. 아래 주소는 문제를 푼 코드를 정리한 노션 주소이다.
Struct와 Class, Protocol을 복습하며 공부를 진행했고, extension은 예전에 책에서 잠깐 보고 사용해 본 적은 없어서 자세히 몰랐는데, 이번 기회에 자세히 공부해봤다.
1. Struct와 Class
- Struct (구조체)
- 값 타입(Value Type)으로, 메모리에서 값을 복사해 사용하는 독립된 인스턴스를 생성
- 상속 불가능
- 주로 데이터를 저장하거나, 간단한 로직을 수행할 때 사용
- Class (클래스)
- 참조 타입(Reference Type)으로, 메모리에서 동일한 인스턴스를 여러 곳에서 참조
- 상속 가능
- 객체지향 프로그래밍의 주요 개념으로 사용
Struct(값 타입)
struct A { // 값 타입
var value = 1
}
var a1 = A()
var a2 = a1
a2.value = 2
print(a1.value) // 1
print(a2.value) // 2
구조체인 a2 = a1 코드는 a1의 값을 복사해 새로운 인스턴스를 생성한 것으로, 두 변수는 완전히 독립적으로 동작한다. 그렇기에 a2.value를 변경해도 a1.value에는 영향을 주지 않는다.
Class(참조 타입)
class B { // 참조 타입
var value = 1
}
var b1 = B()
var b2 = b1
b2.value = 2
print(b1.value) // 2
print(b2.value) // 2
반면, 클래스인 b2 = b1은 같은 인스턴스를 참조하므로, 하나의 값을 변경하면 다른 곳에도 반영되기에 b2.value를 변경하면 b1.value의 값도 변경된다.
Struct vs Class 비교
특징 | Struct | Class |
---|---|---|
메모리 구조 | Stack | Heap |
타입 | 값 타입(Value Type) | 참조 타입(Reference Type) |
상속 | 불가능 | 가능 |
성능 | 메모리 복사로 빠름 | 메모리 참조로 느림 |
2. 프로토콜 (Protocol)
- 프로토콜(Protocol)은 “이 타입은 이런 기능을 제공해야 한다.”는 약속을 정의하는 것이다.
- 구조체(Struct), 클래스(Class), 열거형(Enum)에서 프로토콜을 채택하고 구현할 수 있다.
- 유연하고 재사용성 높은 코드 작성에 유용하다.
- 프로토콜 기반의 설계 방식(Protocol-Oriented Programming)을 가능하게 한다.
프로토콜 사용 예시
protocol Walkable { // 프로토콜 정의
func walk()
}
struct Person: Walkable { // Walkable 프로토콜 채택
func walk() {
print("I'm walking~")
}
}
let person = Person()
person.walk() // I'm walking~
만약, Person
구조체가 Walkable
프로토콜을 채택했지만, walk()
메서드를 구현하지 않으면 컴파일 에러가 발생한다.
그 이유는 Walkable
프로토콜은 walk()
라는 요구사항을 가지고 있기 때문이다. 구조체가 이 요구사항을 구현하지 않으면, 프로토콜의 요구사항을 따르지 않은 것이 되어버려 에러가 발생한다.
3. Extension(확장)
- Swift에서 기존 타입(Protocol, Struct, Class, Enum 등)에 기능을 추가할 수 있게 해주는 문법이다.
- 기존 코드를 수정하지 않고도 새로운 메서드, 연산 프로퍼티, 초기화 메서드 등을 “확장” 할 수 있다.
- 즉, extension은 기존 타입에 기능을 추가할 수 있는 방법으로, 코드를 분리하고 정리하는데 유용하다.
프로토콜은 원래 함수 시그니처(선언)만 정의할 수 있지만, extension을 통해 기본 구현을 제공할 수 있다.
protocol Greetable {
func greet()
}
extension Greetable {
func greet() {
print("Hello!")
}
}
이렇게 extension으로 기본 구현을 해주었다면, Greetable 프로토콜을 채택한 타입이 그 안에 greet()를 직접 구현하지 않아도되며, “Hello!”가 기본 출력된다.
아래와 같이 구조 정리용으로도 사용할 수 있다.
구조체에 모든 걸 한 번에 쓰는 경우
struct User {
let name: String
let age: Int
func introduce() {
print("Hi, I'm \(name)")
}
func isAdult() -> Bool {
return age >= 20
}
}
Extension(확장)으로 나눈 경우
struct User {
let name: String
let age: Int
}
extension User {
func introduce() {
print("Hi, I'm \(name)")
}
}
extension User {
func isAdult() -> Bool {
return age >= 20
}
}
위의 예시에 1번과 2번 둘 다 기능적, 실행 결과 차이 없이 동일하게 동작한다
2번과 같이 나누는 이유는, 큰 프로젝트에서는 기능 단위로 파일이나 extension을 나누는 것이 가독성을 높이고 유지보수에 유리하기 때문에, 한 타입에 여러 extension을 나누어 사용하는 것도 흔하다고 한다.
- Extension을 언제 쓰면 좋을까? 🤔
- 코드를 기능별로 나눠서 사용하고 싶을 때
- 공통 기능 재사용하고 싶을 때 (ex. 모든 뷰 컨트롤에 공통 메서드 추가)
- 프로토콜 기본 동작 제공하고 싶을 때
- Extension의 장점 요약
- 기존 타입에 새로운 기능 추가 가능 (원본 수정 없이)
- 중복 없이 공통 기능 재사용 가능
- 기능별로 코드를 분리하여 가독성과 유지보수 향상
- 프로토콜에 기본 구현 제공 가능
'🖋️ TIL Journal' 카테고리의 다른 글
05.13(화) iOS 사전 캠프 (0) | 2025.05.13 |
---|---|
05.12 (월) iOS 사전캠프 (0) | 2025.05.12 |
05.07 (수) iOS 사전 캠프 (0) | 2025.05.07 |
05.02 (금) iOS 사전 캠프 (1) | 2025.05.02 |
05.01 (목) iOS 사전 캠프 (0) | 2025.05.01 |