붕어빵낫띠
이번 게시글은 붕어빵으로 이해하는데 초점을 두었습니다!
제대로 된 개념이나 예시는 다른데서도 많이 찾아볼 수 있기 때문!!!
클래스와 구조체
클래스(Class)와 구조체(Struct)
🍞 붕어빵을 만드는 틀
틀에는 붕어빵의 모양과 특성이 정의되어 있습니다.
붕어빵 틀에는 어떤 반죽을 사용하고, 어떤 필링(예: 팥, 슈크림)을 넣을지에 대한 정보가 들어있습니다.
class BungeoppangMold {
var filling: String
init(filling: String) {
self.filling = filling
}
}
let redBeanBungeoppang = BungeoppangMold(filling: "Red Bean") //팥붕
let custardBungeoppang = BungeoppangMold(filling: "Custard") //슈붕
인스턴스(Instance)
🍞 틀에서 만들어진 붕어빵입니다
각 인스턴스는 같은 틀에서 나왔기 때문에 기본적으로 같은 모양과 특성을 가지고 있지만,
각각의 붕어빵에 들어간 필링이나 반죽은 다를 수 있습니다.
속성 정리
저장 속성
🍞 붕어빵 속의 팥이나 슈크림 같은 재료에 해당
이 재료들은 붕어빵이 만들어질 때 설정되고, 필요에 따라 나중에 바꿀 수 있습니다.
class Bungeoppang {
var filling: String = "팥" // 저장 속성
}
let bungeoppang = Bungeoppang()
print(bungeoppang.filling) // "팥"
- class / struct 동일
- var, let 으로 선언 가능
- 각 저장 속성마다 고유한 메모리 공간을 가짐
- 초기화 이전에 값을 가지고 있거나, 생성자를 통해 초기화 해야함
지연 저장 속성
💡 저장 속성 앞에 lazy를 붙인다
🍞 붕어빵에 특별한 필링을 넣는 경우, 손님이 특별한 필링을 요청할 때 비로소 필링을 준비하는 것과 같습니다.
⇒ 민트초코붕어빵
class Bungeoppang {
var basePrice: Int = 1000
lazy var specialFilling: String = {
return "민트초코" // 값이 필요할 때만 계산됨
}()
}
let bungeoppang = Bungeoppang()
print(bungeoppang.specialFilling) // "민트초코"
- 값에 대한 접근이 있어야 초기화(메모리 공간 생성)
- lazy var로만 선언 가능(lazy let 안됨)
이유 : let 키워드는 상수로, 초기화된 이후에는 변경할 수 없음
그러나 지연 저장 속성은 초기화 시점이 변수의 첫 사용 시점에 발생하기 때문에 let으로 선언할 수 없다 - 생성자에서 초기화하지 않기 때문에 반드시 기본값이 필요
- ➡ 기본값은 표현식의 어떤 형태든 return값만 일치하면 가능(함수 실행문, 계산식, 클로저 실행문 등)
지연 저장 속성 사용의 2가지 이유
class AView {
var a: Int
// ⭐️ 1) 메모리를 많이 차지할때 -> 메모리 공간의 낭비를 막을 수 있음
lazy var view = UIImageView() // 객체를 생성하는 형태
// ⭐️ 2) 다른 속성을 이용해야할때(다른 저장 속성에 의존해야만 할때)
// -> (초기화 시점이 더 늦으므로, 먼저 초기화되는 저장 속성을 사용가능)
lazy var b: Int = {
return a * 10
}()
init(num: Int) {
self.a = num
}
}
계산 속성
💡 저장속성에 { get블럭, (set블럭) }
🍞 각 붕어빵(인스턴스)별로 다른 속성을 기반으로 계산됩니다. 예 : 붕어빵 칼로리 계산
class Bungeoppang {
var basePrice: Int
var extraFillingPrice: Int
init(basePrice: Int, extraFillingPrice: Int) {
self.basePrice = basePrice
self.extraFillingPrice = extraFillingPrice
}
var totalPrice: Int {
get {
return basePrice + extraFillingPrice
}
set(newTotalPrice) {
if newTotalPrice >= basePrice {
extraFillingPrice = newTotalPrice - basePrice
} else {
print("New total price must be at least the base price.")
}
}
}
}
let bungeoppang = Bungeoppang(basePrice: 1000, extraFillingPrice: 500)
print(bungeoppang.totalPrice) // 1500
bungeoppang.totalPrice = 2000
print(bungeoppang.extraFillingPrice) // 1000
bungeoppang.totalPrice = 800 // "New total price must be at least the base price."
print(bungeoppang.extraFillingPrice) // 1000 (no change)
- 메서드가 아닌, 속성방식으로 구현할 시의 장점과 이유
관련이 있는 두가지 메서드(함수)를 한번에 구현할 수 있다.
그리고 외부에서 보기에 속성 이름으로 설정 가능하므로 보다 명확해 보임 - 따라서, 계산 속성은 메서드를 개발자들이 보다 읽기 쉽고, 명확하게 쓸 수 있는 형태인 속성으로 변환해 놓은 것이다.
- 실제로, 계산 속성은 겉모습은 속성(변수)형태를 가진 메서드(함수)임 ⭐️
- 계산 속성은 실제 메모리 공간을 가지지 않고,
해당 속성에 접근했을때 다른 속성에 접근해서 계산한후,
그 계산 결과를 리턴하거나 세팅하는 메서드 이다. - 주의점
항상 변하는 값이므로, var로 선언해야함 (let로 선언불가)
자료형 선언을 해야함(형식추론 형태 안됨) (메서드이기 때문에 파라미터, 리턴형이 필요한 개념)
get은 반드시 선언 해야함(값을 얻는 것은 필수, 값을 set하는 것은 선택)
타입 속성
: 타입 전체에 저장되는 속성
🍞 모든 붕어빵에 공통적으로 적용되는 반죽의 종류처럼 틀에 정의된 속성입니다.
모든 붕어빵이 같은 반죽을 사용할 경우, 이 속성은 변하지 않습니다.
- 인스턴스에 속한 속성이 아니고, 타입자체에 속한 속성이기에 내(주의)/외부에서 Type.property로 접근해야함
- 저장 타입 속성을 주로 사용
- 지연 속성의 성격을 가짐 ⭐️
저장 타입 속성
🍞 붕어빵 틀 전체에 적용되는 특성
class Bungeoppang {
static var costOfIngredients: Int = 1000 // 저장 타입 속성
}
- 모든 인스턴스가 동일하게 가져야하는 보편적인 속성이거나, 공유해야하는 성격에 가까운 저장 속성을 저장 타입 속성으로 선언
- static 키워드 사용 (상속시) 재정의 불가(class 키워드 사용불가)
- let / var 선언 둘다 가능(저장 타입 속성)
- 항상 기본값(초기값) 필요(생성자에 의한 값 설정 과정이 없으므로)
- 자체적으로 지연(lazy) 속성의 성격을 가지므로, 호출시 메모리 할당
계산 타입 속성
🍞 붕어빵 틀 전체에 적용되지만, 다른 정보를 기반으로 계산되는 특성입니다.
class Bungeoppang {
static var numberOfPiecesPerBatch: Int {
return 10 // 계산 타입 속성
}
}
- (상속시)재정의 가능(class 키워드 사용 시에만)
- static(재정의 X) 또는 class(재정의 O) 키워드 사용
- var 키워드만 사용 가능(계산 타입 속성)
- 메서드이기 때문에 타입에 메모리 공간이 할당되어 있지 않음(계산 속성)
속성 감시자
🍞 붕어빵 속 필링이 변할 때 알람을 울리는 장치와 같습니다. 속성이 변경될 때 특정 동작을 수행합니다.
class Profile{
...
var sMessage: String = "메세지" {
willset{
print("\\(sMessage)->\\(newValue)")// -> 새 값 저장되기 직전에 호출
}
didset{
print("\\(oldValue)->\\(sMessage)")// -> 새 값 저장 직후 호출
}
}
}
- willSet: 새로운 값이 저장되기 직전에 호출. 기본적으로 newValue라는 이름으로 새로운 값을 참조할 수 있음
- didSet: 새로운 값이 저장된 직후에 호출 기본적으로 oldValue라는 이름으로 이전 값을 참조할 수 있음
- 일반적으로는 willSet 또는 didSet 중에서 한가지만 구현
(실제 프로젝트에서는 didSet을 많이 사용) - 속성 감시자를 사용하는 이유
- 변수 변하면, 변경 내용을 반영하고 싶을때(업데이트)
- (실제 프로젝트에서 쉽게 이해가 되는 부분임)
- 예시) 상태메세지 변경
메서드 정리
인스턴스 메서드
: 특정 인스턴스와 관련된 함수
🍞 각 붕어빵에 대해 수행할 수 있는 동작입니다. 예를 들어, 붕어빵을 데우거나 자르는 등의 행동입니다.
// 인스턴스 메서드
func describe() -> String {
return "This bungeoppang has \(filling) filling."
}
- 인스턴스 상태를 변경하거나 읽는 작업을 수행할 수 있습니다.
- mutating 키워드
- 값타입의 인스턴스 메서드 내에서 자신의 속성값 수정은 원칙적 불가하기 때문에 해당 키워드를 붙여줘야함
타입 메서드
🍞 붕어빵 틀 전체에 적용되는 방법입니다.
예를 들어, 모든 붕어빵의 필링 종류를 알아내는 방법 같은 것입니다. 이는 붕어빵 개별 인스턴스가 아닌 틀 자체에 적용됩니다.
static func description() -> String {
return "Bungeoppang is a Korean fish-shaped pastry."
}
- static 키워드로 선언하며, 클래스의 경우 class 키워드를 사용해 재정의할 수 있음
- 주로 타입 수준에서의 기능 제공이나 공용 데이터 관리에 사용 → 인스턴스 기능이 아닌, 타입 자체에 필요한 기능을 구현할때 주로 사용
서브스크립트
🍞 여러 붕어빵이 나열된 상황에서 특정 붕어빵을 골라내는 방법입니다. 예를 들어, 팥이 들어간 붕어빵만 고르거나, 특정 번호의 붕어빵을 선택할 수 있는 기능입니다.
- 컬렉션, 리스트, 시퀀스 같은 타입에서 인덱스를 통해 값을 설정하거나 가져올 수 있도록 하는 문법 배열이나 딕셔너리와 같은 컬렉션 타입에서 자주 사용됨
접근 제어
🍞 붕어빵의 레시피를 보호하는 것과 같습니다. 일부 정보는 공개하고(public), 일부는 가족들만 알고(internal), 또 일부는 오직 붕어빵 주인만 아는(private) 비밀 레시피로 관리합니다.
싱글톤 패턴
🍞 특정 붕어빵 틀(예: 특별한 한정판 붕어빵 틀)이 하나만 존재하도록 보장하는 방법입니다.
이 틀로 만든 붕어빵은 항상 같은 틀에서 나옵니다.
class BungeoppangManager {
static let shared = BungeoppangManager()
private init() {
// Private initializer prevents creating new instances from outside
}
func createBungeoppang(filling: String) -> Bungeoppang {
return Bungeoppang(filling: filling)
}
}
- 앱 구현시에, 유일하게 한개만 존재하는 객체가 필요한 경우에 사용
- (특정한 유일한 데이터/관리 객체가 필요한 경우)
- 한번 생성된 이후에는 앱이 종료될때까지, 유일한 객체로 메모리에 상주
'iOS' 카테고리의 다른 글
[복습] Part 13 타입 캐스팅 | is, as 연산자, 상속, 다형성, Any, AnyObject (0) | 2024.09.11 |
---|---|
Swift 입력 받기 (0) | 2024.09.08 |
[앨런 Swift문법 마스터 스쿨] 3주차 시험 오답 노트 (0) | 2024.08.05 |
[앨런 Swift문법 마스터 스쿨] 열거형 case 패턴, 속성과 메서드 정리 복습! (2) | 2024.07.27 |
[앨런 swift문법 마스터 스쿨] 클래스, 초기화 함수 init, self (2) | 2024.07.22 |