** edwith - Swift 프로그래밍 입문 강의 참고 **
# 클로저 #
- 실행가능한 코드 블럭
- 함수와 다르게 이름정의는 필요하지 않지만, 매개변수 전달과 변환 값이 존재할 수 있다는 점이 동일
- 함수는 이름이 있는 클로저
- 일급객체로 전달인자, 변수, 상수 등에 저장 및 전달이 가능
// 클로저 기본 문법
{ (/* 매개변수 목록*/) -> /* 반환 타입 */ in
/* 실행 코드 */
}
// 클로저 사용
// sum이라는 상수에 클로저 할당
let sum: (Int, Int) -> Int = { (a: Int, b: Int) in
return a + b
}
let sumResult: Int = sum(1, 2)
print(sumResult) // 3
// 함수의 전달인자로서의 클로저
// 함수 내부에서 원하는 코드블럭을 실행할 수 있습니다.
let add: (Int, Int) -> Int
add = { (a: Int, b:Int) in
return a + b
}
let substract: (Int, Int) -> Int
substract = { (a: Int, b: Int) in
return a - b
}
let divide: (Int, Int) -> Int
divide = { (a: Int, b: Int) in
return a / b
}
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
return method(a, b)
}
var calculated: Int
calculated = calculate(a: 50, b: 10, method: add)
print(calculated) // 60
calculated = calculate(a:50, b:10, method: substract)
print(calculated) // 40
calculated = calculate(a:50, b:10, method: divide)
print(calculated) // 5
calculated = calculate(a: 50, b:10, method: { (left: Int, right: Int) -> Int in
return left * right
} )
print(calculated) // 500
# 다양한 클로저 표현 #
- 후행 클로저 : 함수의 매개변수 마지막으로 전달되는 클로저는 후행 클로저(trailing closure)로, 함수 밖에 구현할 수 있습니다.
- 반환타입 생략 : 컴파일러가 클로저의 타입을 유추할 수 있는 경우 매개변수, 반환 타입을 생략할 수 있습니다.
- 단축 인자 이름 : 전달인자의 이름이 굳이 필요없고, 컴파일러가 타입을 유추할 수 있는 경우 축약된 전달인자 이름($0, $1, $2...)을 사용할 수 있습니다.
- 암시적 반환 표현 : 반환 값이 있는 경우, 암시적으로 클로저의 맨 마지막 줄은 return 키워드를 생략하더라도 반환 값으로 취급합니다.
/* 기본 클로저 */
func calculate(a: Int, b:Int, method: (Int, Int) -> Int) -> Int {
return method(a, b)
}
var result: Int
/* 1. 후행 클로저 */
// 클로저가 함수의 마지막 전달인자 일 때, 마지막 매개변수 이름(method)를 생략한 후 함수 소괄호 외부에 클로저를 구현할 수 있습니다.
result = calculate(a: 10, b:10) { (left: Int, right: Int) -> Int in
return left + right
}
print(result) // 20
/* 2. 반환타입 생략 */
// calculate(a:b:method:) 함수의 method 매개변수는 Int 타입을 반환할 것이라는 사실을 컴파일러도 추측할 수 있기 때문에 굳이 클로저에서 반환타입을 명시해 주지 않아도 됩니다.
// 대신 in 키워드는 생략할 수 없습니다.
result = calculate(a: 10, b: 10, method: { (left:Int, right:Int) in
return left + right
} )
print(result) // 20
/* 3. 단축 인자 이름 */
// 클로저의 매개변수 이름이 굳이 불필요하다면 단축 인자이름을 활용할 수 있습니다.
// 단축 인자이름은 클로저의 매개변수의 순서대로 $0, $1, $2... 처럼 표현합니다.
result = calculate(a: 10, b: 10, method: {
return $0 + $1
} )
result = calculate(a: 10, b:10) { // + 후행 클로저
return $0 + $1
}
print(result) // 20
/* 4. 암시적 반환 표현 */
// 클로저가 반환하는 값이 있다면 클로저의 마지막 줄의 결과값은 암시적으로 반화값으로 취급
result = calculate(a: 10, b: 10) {
$0 + $1
}
result = calculate(a: 10, b: 10) { $0 + $1 }
print(result) // 20
# 프로퍼티 #
프로퍼티의 종류
- 인스턴스 저장 프로퍼티
- 타입 저장 프로퍼티
- 인스턴스 연산 프로퍼티
- 타입 연산 프로퍼티
- 지연 저장 프로퍼티
정의와 사용
- 프로퍼티는 구조체, 클래스, 열거형 내부에 구현 가능 (열거형 내부에는 연산 프로퍼티만 구현 가능)
- 연산 프로퍼티는 var로만 선언 가능
- 연산 프로퍼티를 읽기 전용으로는 구현할 수 있지만, 쓰기 전용으로는 구현 불가능
- 연산 프로퍼티를 읽기 전용으로 구현하려면 get 블럭 작성. (읽기 전용은 get 블럭 생략 가능)
- 읽기, 쓰기 모두 가능하게 하려면 get 블럭과 set 블럭 모두 구현
- set 블럭에서 암시적 매개변수 newValue 사용 가능
struct Student {
// 인스턴스 저장 프로퍼티
var name: String = ""
var 'class': String = "튤립"
var koreanAge: Int = 1
// 인스턴스 연산 프로퍼티
var westernAge: Int {
get {
return koreanAge - 1
}
set(inputValue) {
koreanAge = inputValue + 1
}
}
// 읽기전용 인스턴스 연산 프로퍼티 - 인스턴스 메서드 selfIntroduce()를 간단하게 대체 가능
var selfIntroduction: String {
get {
return "저는 \(self.class)반 \(name)입니다."
}
}
// 타입 저장 프로퍼티
static var typeDescription: String = "학생"
// 읽기전용 타입 연산 프로퍼티 - 읽기전용에서는 get 생략 가능
static var selfIntroduction: String {
return "학생 타입입니다."
}
print(Student.selfIntroduction) // 학생 타입입니다.
// 인스턴스 메서드
func selfIntroduce() {
print("저는 \(self.class)반 \(name)입니다.")
}
// 타입 메서드
static func selfIntroduce() {
print("학생 타입입니다.")
}
// 인스턴스 생성
var been: Student = Student()
been.koreanAge = 24
// 인스턴스 저장 프로퍼티 사용
been.name = "been"
print(been.name) // been
// 인스턴스 연산 프로퍼티 사용
print(been.selfIntroduction) // 저는 튤립반 been입니다.
}
응용
struct Money {
var currencyRate: Double = 1100
var dollar: Double = 0
var won: Double {
get {
return dollar * currencyRate
}
set {
dollar = newValue / currencyRate
}
}
}
var moneyInMyPocket = Money()
moneyInMyPocket.won = 11000
print(moneyInMyPocket.won) // 11000
moneyInMyPocket.dollar = 5
print(moneyInMyPocket.won) // 5500
# 프로퍼티 감시자 #
- 프로퍼티 감시자 사용 시, 프로퍼티의 값이 변경될 때 원하는 동작 수행 가능
- 값이 변경되기 직전, willSet 블럭이 호출 됨.
- 값이 변경된 직후에는 didSet 블럭이 호출 됨.
- 둘 중 필요한 하나만 구현해 주어도 무관
- 변경되려는 값이 기존 값과 똑같더라도 프로퍼티 감시자는 항상 동작
- willSet 블럭에서는 암시적 매개변수 newValue를, didSet 블럭에서는 oldValue를 사용할 수 있습니다.
- 프로퍼티 감시자는 연산 프로퍼티에는 사용 불가능
- 프로퍼티 감시자는 함수, 메서드, 클로저, 타입 등의 지역/전역 변수에 모두 사용 가능
// 정의 및 사용
struct Money {
// 프로퍼티 감시자 사용
var currencyRate: Double = 1100 {
willSet(newRate) {
print("환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다.")
}
didSet(oldRate) {
print("환율이 \(oldRate)에서 \(currencyRate)으로 변경되었습니다.")
}
}
// 프로퍼티 감시자 사용
var dollar: Double = 0 {
// willSet의 암시적 매개변수 이름 newValue
willSet {
print("\(dollar)달러에서 \(newValue)달러로 변경될 예정입니다.")
}
// didSet의 암시적 매개변수 이름 oldValue
didSet {
print("\(oldValue)달러에서 \(dollar)달러로 변경되었습니다.")
}
}
// 연산 프로퍼티
var won: Double {
get {
return dollar * currencyRate
}
set {
dollar = newValue / currencyRate
}
}
}
var moneyInMyPocket: Money = Money()
// 환율이 1100.0에서 1150.0으로 변경될 예정입니다.
moneyInMyPocket.currencyRate = 1150
// 환율이 1100.0에서 1150.0으로 변경되었습니다.
// 0.0달러에서 10.0달러로 변경될 예정입니다.
moneyInMyPocket.dollar = 10
// 0.0달러에서 10.0달러로 변경되었습니다.
print(moneyInMyPocket.won) // 11500.0
'iOS > Swift' 카테고리의 다른 글
Swift-6. 옵셔널 체이닝, nil 병합 (0) | 2023.02.24 |
---|---|
Swift-5. 인스턴스 생성 및 소멸 (0) | 2023.02.24 |
Swift-3. 구조체, 열거형 (0) | 2023.02.24 |
Swift-2. 반복문, 옵셔널/옵셔널체이닝/옵셔널바인딩 (0) | 2023.02.24 |
Swift-1. 변수, 리스트, 함수 (0) | 2023.02.24 |
댓글