본문 바로가기
아이폰 개발/Swift

swift 기초 - 클로저 , 프로퍼티, 프로퍼티 감시자

by 인생여희 2021. 3. 4.

swift 기초 - 클로저 , 프로퍼티, 프로퍼티 감시자

 

[1]클로저

 

 코드의 블럭

 일급 시민

 변수, 상수 등으로 저장, 전달인자로 전달이 가능

 함수 : 이름이 있는 클로저

 

 정의

 {

    (매개변수 목록) -> <반환타입> in <실행코드>

 }

 

[1-1] 함수를 사용한다면

func sumFunction(a:Int , b:Int) -> Int {
    return a+b
}

var sumResult: Int = sumFunction(a: 1, b: 2)

print(sumResult) //3

 

[1-2] 클로저 정의 및 할당

var sumCloser : (Int, Int) -> Int = {
    
    //매개변수 목록 -> 반환타입
    (a:Int , b:Int) -> Int in
    
    //실행코드
    return a + b
}

 

[1-3] 클로저의 사용

sumResult = sumCloser(1, 2)

print(sumResult) //3

 

[1-4] 함수는 클로저의 일종

//sumResult 변수에 함수도 할당가능하다.
sumCloser = sumFunction(a:b:)

sumResult = sumCloser(1,2)

print(sumResult) //3

 

 

[1-5] 함수의 전달인자로서의 클로저

//더하기 클로저
let add: (Int, Int) -> Int

add = {
    (a:Int, b:Int) -> Int in
    return a + b
}

//빼기 클로저
let substract : (Int, Int) -> Int
substract = {
    (a:Int, b:Int) -> Int in
    return a - b
}

//나누기 클로저
let divide:(Int, Int) -> Int
divide = {
    (a:Int, b:Int) -> 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)

//빼기
calculated = calculate(a: 50, b: 10, method: substract)
print(calculated)

//나누기
calculated = calculate(a: 50, b: 10, method: divide)
print(calculated)

 

[2] 클로저 고급

 

[2-1] 후행 클로저

 클로저가 함수의 마지막 전달인자라면

 마지막 매개변수 이름을 생략한 후

 함수의 소괄호 외부에 클로저를 구현할 수 있다.

 

calculated =
    calculate(a: 50, b: 10){
        
        (left:Int, right:Int) -> Int in
        return left - right
}

print(calculated) //40

 

[2-2] 반환타입 생략

 calculate 함수의 method 매개변수는

 Int 타입을 반환할 것이라는 사실을 컴파일러도 알기때문에

 굳이 클로저에서 반환타입을 명시해 주지 않아도 된다.

 대신 in 키워드는 생략할 수 없다(!)

 

calculated =
calculate(a: 10, b: 10, method: {
    
    (left:Int, right:Int) in
    return left + right
})

print(calculated) //20

 

 

[2-3] 후행클로저와 함께 사용가능

calculated =
    calculate(a: 10, b: 10){
    
    (left:Int, right:Int) in
    return left + right
    
}

 

[2-4] 단축인자 이름

클로저의 매개변수 이름이 굳이 불필요하다면

단축인자 이름을 사용할 수 있다.

단축인자 이름은 $0, $1 .. 처럼 표현가능하다.

 

calculated = calculate(a: 10, b: 10, method: {
    return $0 + $1
})

print(calculated) //20

 

 

[2-5] 후행클로저와 함께 사용가능

calculated = calculate(a: 10, b: 10){
   return $0 + $1
}

 

 

 [2-6] 암시적 반환 표현

 클로저가 반환하는 값이 있다면

 클로저의 마지막 줄의 결과값은 암시적으로 반환값으로 취급한다.

 

calculated = calculate(a: 10, b: 10){
    $0 + $1
}

 

 

[2-7]  축약하지 않은 클로저 문법과 축약 후의 문법 비교

calculated   = calculate(a: 10, b: 10, method: { (left: Int, right: Int) -> Int in
    return left + right
})

calculated = calculate(a: 10, b: 10) { $0 + $1 }

print(calculated) // 20

 

 

[3] 프로퍼티

 

 프로퍼티는 구조체, 클래스, 열거형 내부에 구현가능하다.

 다만 열거형 내부에는 연산 프로퍼티만 구현할 수 있다.

 연산 프로퍼티는 var 로만 선언할 수 있다.

 

 

[3-1] 프로퍼티 , set, get 메소드 정의

//학생 구조체
struct Student {
    
    //인스턴스 저장 프로퍼티
    var name:String = ""
    var className : String = "Swift"
    var korAge : Int = 0        //한국나이
    
    
    //인스턴스 연산프로퍼티
    //미국 나이
    var westenAge:Int {
        
        get{
            return korAge - 1
        }
        
        
        set(inputValue){
            korAge = inputValue + 1
        }
        
    } //미국나이 끝
    
    
    
    //타입 저장 프로퍼티
    static var typeDescription:String = "학생"
    
    //인스턴스 메소드
//    func selfInstroduction() {
//        print("저는 \(self.className)반 \(name)입니다.")
//    }
    
    //읽기전용 인스턴스 연산 프로퍼티 - 인스턴스 메소드의 역할과 같다.
    var selfInstroduction:String {
        get{
            return "저는 \(self.className)반 \(name)입니다."
        }
    }
    
    
    //타입 메서드
    static func selfIntroduce(){
        print("학생 타입입니다. - 타입메소드")
    }
    
    //읽기 전용 타입 연산 프로퍼티
    //읽기 전용에서는 get을 생략할 수 있다.
    static var selfIntroduction:String{
        return "학생 타입입니다.(타입 연산 프로퍼티)"
    }
}

 

 

[3-2] 프로퍼티 사용하기

//타입연산 프로퍼티 사용
print(Student.selfIntroduction) //학생 타입입니다.(타입 연산 프로퍼티)

//인스턴스 생성
var person : Student = Student()
person.korAge = 10

//인스턴스 저장 프로퍼티 사용
person.name = "ggg"
print(person.name) //ggg

//인스턴스 연산 프로퍼티
print(person.selfInstroduction) //저는 Swift반 ggg입니다.

print("제한국 나이는 \(person.korAge) 이고, 미국 나이는 \(person.westenAge) 입니다.")
//제한국 나이는 10 이고, 미국 나이는 9 입니다.

 

[3-3] 프로퍼티 응용하기

struct Money {
    var  currencyRate:Double = 1100
    var dollar:Double = 0
    var won : Double{
        
        get{
            return dollar * currencyRate
        }
        
        set{
            dollar = newValue / currencyRate
        }
        
    }
}

var moneyInMyPocket = Money()

print(moneyInMyPocket.dollar)//0.0

moneyInMyPocket.won = 11000.0
print(moneyInMyPocket.won)//11000.0
print(moneyInMyPocket.dollar)//10.0


moneyInMyPocket.dollar = 10
print(moneyInMyPocket.won)//11000.0


// 지역변수, 전역변수
/*
 저장프로퍼티와 연산프로퍼티의 기능은
 함수, 메서드, 클로저, 타입 등의 외부에 위치한
 지역/전역 변수에도 모두 사용가능하다.
 */

var aaa:Int = 100
var bbb:Int = 200
var sum:Int{
    return aaa + bbb
}

print(sum) //300

 

[4] 프로퍼티 감시자

 

프로퍼티 감시자를 사용하면 프로퍼티 값이 변경될 때 원하는 동작을 수행할 수 있다.

 

 

[4-1] 프로퍼티 감시자 정의

struct MoneyAgain {
    
    //프로퍼티 감시자 사용
    var currencyRate:Double = 1100{
        
        //변경 전
        willSet(newRate){
            print("환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다.")
        }
            
        //변경 후
        didSet(oldRate){
            print("환율이 \(oldRate)에서 \(currencyRate)으로 변경되었습니다.")
        }
        
    } // - end
    
    
    //프로퍼티 감시자 사용
    var dollar:Double = 0 {
        //변경 전
        willSet{
            //willSet의 암시적 매개변수 이름 newValue
            print("\(dollar) 달러에서 \(newValue)달러로 변경될 예정입니다.")
        }
        
        //변경 - 후
        didSet{
            //didSet의 암시적 매개변수 이름 oldValue
            print("\(oldValue) 달러에서 \(dollar)로 변경되었습니다.")
        }
    }// -end
    
    //연산 프로퍼티
    var won:Double {
        
        get{
            return dollar * currencyRate
        }
        
        set{
            dollar = newValue / currencyRate
        }
        
        /*
                프로퍼티 감시자와 연산프로퍼티 기능을 동시에 사용할 수 없다.
            */
        
    }
    
}// struct - end

 

 

[4-2] 프로퍼티 감시자 사용

var moneyInMyPocketAgain : MoneyAgain = MoneyAgain();

//환율이 1100.0에서 1150.0으로 변경될 예정입니다.
moneyInMyPocketAgain.currencyRate = 1150
//환율이 1100.0에서 1150.0으로 변경되었습니다.

//0.0 달러에서 10.0달러로 변경될 예정입니다.
moneyInMyPocketAgain.dollar = 10
//0.0 달러에서 10.0로 변경되었습니다.

print(moneyInMyPocketAgain.won) //11500.0

/*
 프로퍼티 감시자 기능은 함수, 메서드, 클로저, 타입 등
 외부에 위치한 지역/전역 변수에도 모두 사용가능하다.
 */
var ccc:Int = 100 {
    
    willSet{
        print("\(ccc)에서 \(newValue)로 변경될 예정입니다.")
    }
    
    didSet{
        print("\(oldValue)에서 \(ccc)로 변경되 었습니다.")
    }
    
}

//100에서 200로 변경될 예정입니다.
ccc = 200
//100에서 200로 변경되 었습니다.

 

 

test2.zip
0.02MB

 

 

 

참고

blog.yagom.net/