1️⃣ To do list
오전
9시 - 코드카타 : 2024.03.11 - [Swift/Code Kata (알고리즘)] - [Swift|코드카타] (프로그래머스) #37. 행렬의 덧셈
10시 - 발제 zoom
오후 1
문법 심화 강의 (1-1 ~ 1-6)
헷갈리는 개념 해결 - 연산프로퍼티, 클로저
2️⃣ 배운 것
1. 연산프로퍼티
프로퍼티는 저장프로퍼티와 연산프로퍼티 두 개로 나눌 수 있다.
- 저장 프로퍼티 : let 또는 var로 값을 선언
let name: String = "민수"
var age: Int = 10
- 연산 프로퍼티 : 매번 연산을 해야하므로 var로만 선언할 수 있다.
var sum: Int {
// get : 어떤 저장 프로퍼티의 값을 연산해서 return할 것인지 (sum 값을 가져옴)
get {
return x + y
}
// set : 파라미터로 받은 값을 어떤 저장 프로퍼티에 어떻게 설정할 것인지를 구현 (sum에 값을 넣어줌)
set(newValue) {
z = newValue + 100
}
}
// get 실행
print(sum) // 출력값: 30
// set 실행
sum = 20 // sum이 변경되며 set 실행됨
print(z) // 출력값: 120
# 연산 프로퍼티는 클로저가 아니다
연산 프로퍼티를 정의할 때 클로저가 사용될 뿐, 클로저는 아니다.
**get, set은 클로저 syntax로 정의된다.
<튜터님 추가 설명>
클로저를 이용해서 가능한 한 가지 중요하고 유용한 특성은 연산 프로퍼티는 runtime 환경에서 dynamic 으로 실행됩니다.
즉, 해당 변수가 직접 접근되거나 수정될 때, 해당 값이 결정되고 읽어집니다. 내부적으로 어떻게 하는 지는 모르겠지만, 컴파일할 때 get set 클로저를 가리키는 포인터를 메모리 어딘가(아마 관련 타입 테이블이겠죠)에 저장하고 있다가 변수가 쓰일 때 필요한 클로저를 실행시키지 않을까요
그래서 sum 이 Int 타입인 건 이상하지 않아요. get 클로저 실행결과 반환 타입을 의미하니까요
결론은
연산 프로퍼티는 클로저와 관련이 있나요? 네 있습니다. 연산프로퍼티를 정의할 때 클로저를 사용하는 것이지 프로퍼티 자체가 클로저는 아닙니다.
2. 프로퍼티 옵저버
프로퍼티 옵저버는 말 그대로 프로퍼티를 관찰하다가 값이 변하면 실행된다.
값이 변경되기 직전에 호출되는 willSet,
값이 변경된 직후에 호출되는 didSet이 있다.
새로운 프로퍼티 값은 newValue로, 이전 프로퍼티 값은 oldValue로 제공된다.
예제 1
var name: String = "Unknown" {
willSet {
print("현재 이름 = \(name), 바뀔 이름 = \(newValue)")
//myProperty의 값이 변경되기 직전에 호출, newVal은 변경 될 새로운 값
}
didSet {
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldValue)")
//myProperty의 값이 변경된 직후에 호출, oldVal은 변경 전 myProperty의 값
}
}
name = "Peter"
// willSet이 먼저 실행됨
// 현재 이름 = Unknown, 바뀔 이름 = Peter
// 현재 이름 = Peter, 바뀌기 전 이름 = Unknown
예제 2
class UserAccount {
var username: String
var password: String
var loginAttempts: Int = 0 {
didSet {
if loginAttempts >= 3 {
print("로그인 시도가 3회 이상 실패하였습니다. 계정이 잠겼습니다.")
lockAccount()
}
}
}
var isLocked: Bool = false {
didSet {
if isLocked {
print("계정이 잠겼습니다.")
} else {
print("계정이 잠금 해제되었습니다.")
}
}
}
init(username: String, password: String) {
self.username = username
self.password = password
}
func login(with enteredPassword: String) {
if enteredPassword == password {
print("로그인 성공!")
loginAttempts = 0 // 로그인 성공 시 로그인 시도 횟수 초기화
} else {
print("잘못된 비밀번호입니다.")
loginAttempts += 1 // 로그인 실패 시 로그인 시도 횟수 증가
}
}
private func lockAccount() {
isLocked = true
}
func unlockAccount() {
isLocked = false
}
}
// 사용자 계정 생성
let user = UserAccount(username: "user123", password: "password123")
// 로그인 시도
user.login(with: "wrongpassword")
// 출력:
// 잘못된 비밀번호입니다.
user.login(with: "wrongpassword")
// 출력:
// 잘못된 비밀번호입니다.
user.login(with: "wrongpassword")
// 출력:
// 잘못된 비밀번호입니다.
// 로그인 시도가 3회 이상 실패하였습니다. 계정이 잠겼습니다.
// 계정이 잠겼습니다.
// 계정 잠금 해제
user.unlockAccount() // 계정이 잠금 해제되었습니다.
3. 다양한 배열 초기화 방법
배열 초기화 방법 두 가지
var a: [Int] = [] // [] (빈 어레이)
var a = [Int]() // [] (빈 어레이)
배열 초기화와 헷갈릴 수 있는 코드
var a: [Int] // 초기화 안 돼서 바로 값 추가 못함
var a = [Int] // error
var a = [Int].self // Array<Int> (타입)
'Swift > TIL(TodayILearned)' 카테고리의 다른 글
[Swift|TIL] 240315 - dropFirst(_:) / suffix(_:) /shuffle() / ArraySubsequence(=ArraySlice) 타입 (부분열)을 Array타입으로 초기화 / 개인과제(2) 리뷰 (0) | 2024.03.15 |
---|---|
[Swift|TIL] 240312 - 접근 제한자, extension, subscript (1) | 2024.03.12 |
[Swift|코드카타] (프로그래머스) 입문 #35. 부족한 금액 계산하기 - 수학 공식을 활용하여 더 가볍게 코딩! (0) | 2024.03.08 |
[Swift|TIL] 240307 회고 (0) | 2024.03.08 |
[Swift|TIL] 240306 회고 - 클래스, 구조체, 열거형 비교 (2) | 2024.03.06 |