새소식

iOS/Swift

[Swift] 프로퍼티와 메서드

  • -
참조 :  Swift 스위프트 프로그래밍 3판 Swift 5, 저자 야곰 (한빛미디어) , The Swift Programming Language Swift 5.6 Edition (iBooks)(https://books.apple.com/kr/book/the-swift-programming-language-swift-5-6/id881256329)

 

 

 

프로퍼티 (Property)


- 프로퍼티 : 클래스, 구조체 또는 열거형 등에 관련된 값

- 프로퍼티의 종류

  1. 저장 프로퍼티 : 인스턴스의 변수 또는 상수, 구조체와 클래스에서 사용가능
  2. 연산 프로퍼티 : 값을 저장한 것이 아니라 특정 연산을 실행한 결괏값, 클래스와 구조체, 열거형에서 사용 가능
  3. 타입 프로퍼티 : 특정 타입에 사용되는 프로퍼티

- 프로퍼티 감시자 : 프로퍼티의 값이 변화하는 것을 감시, 프로퍼티의 값이 변할 때 값의 변화에 따른 특정 작업을 실행, 

저장 프로퍼티에 적용 가능, 부모 클래스로 부터 상속 가능

 

 

 

저장 프로퍼티


- 클래스 또는 구조체의 인스턴스와 연관된 값을 저장하는 가장 단순한 개념의 프로퍼티

- var 키워드를 사용하면 변수 저장 프로퍼티

- let 키워드를 사용하면 상수 저장 프로퍼티

- 구조체는 프로퍼티에 맞는 이니셜라이저를 자동으로 제공, 클래스에서는 그렇지 않아 클래스의 저장 프로퍼티에 초깃값을 지정하면 따로 사용자 정의 이니셜라이저를 구현해줄 필요 없음

- 저장 프로퍼티에 옵셔널이 초깃값이면 넣어주지 않아도 됨

※ 인스턴스를 생성할 때 이니셜라이저를 통해 초깃값을 보내야 하는 이유

- 프로퍼티가 옵셔널이 아닌 값으로 선언되어 있기 때문 → 인스턴스는 생성할 때 프로퍼티가 값이 있는 상태여야 함

 

 

// 저장프로퍼티에서 초깃값 지정
import UIKit

struct CoordinatePoint{
    var x: Int = 0
    var y: Int = 0
}

// 프로퍼티의 초깃값을 할당했다면 굳이 전달인자로 초깃값을 넘길 필요가 없음
let sonPoint: CoordinatePoint = CoordinatePoint()

let kimPoint: CoordinatePoint = CoordinatePoint(x: 10, y: 5)

 

 

 

지연 저장 프로퍼티(Lazy Stored Properties)


- 호출이 있어야 값을 초기화함 → lazy 키워드 사용

- 상수는 인스턴스 생성 전에 초기화해야 함→ 필요할 때 값을 할당하는 지연 저장 프로퍼티와는 맞지 않음

- var 키워드 사용하여 변수로 정의

-  주로 복잡한 클래스나 구조체를 구현할 때 많이 사용

- 불필요한 성능 저하, 공간 낭비 줄임

 

// 저장 프로퍼티에서 초깃값 지정
struct CoordinatePoint{
	var x: Int = 0
	var y: Int = 0
}

class Position{
	lazy var point: CoordinatePoint = CoordinatePoint()
    let name: String
    init(name: String){
    	self.name = name
        }
}

let kimPosition: Position = Position(name: "kim")
print(kimPosition.point) // CoordinatePoint(x: 0, y: 0)

 

※ 다중 스레드 환경에서 지연 저장 프로퍼티에 동시다발적으로 접근할 때 한 번만 초기화된다는 보장이 없음,  생성되지 않은 지연 저장
프로퍼티에 많은 스레드가 비슷한 시점에 접근한다면 → 여러 번 초기화될 수 있음

 

 

연산 프로퍼티(Computed Properties)


- 특정 상태에 따른 값을 연산하는 프로퍼티

- 인스턴스 내/외부의 값을 연산하여 적절한 값을 돌려주는 접근자(getter)의 역할, 은닉화된 내부의 프로퍼티 값을 간접적으로
설정하는 설정자(setter) 역할도 가능

- 접근자인 get 메서드만 구현해둔 것처럼 읽기 전용 상태로 구현하기 쉽지만, 쓰기 전용 상태로 구현할 수 없다는 단점

 

struct CoordinatePoint{
	var x: Int = 0
	var y: Int = 0
    
    var oppositionPoint: CoordinatePoint{
    	get{
        	return CoordinatePoint(x: -x, y: -y)
            }
     	set(opposite) {
        	x = -opposite.x
        	y = -opposite.y
        }
    }
}

var kimPoint: CoordinatePoint = CoordinatePoint(x: 10, y: 20)
print(kimPoint) // CoordinatePoint(x: 10, y: 20)

kimPoint.oppositionPoint = CoordinatePoint(x: 15, y: 10)
print(kimPoint) // CoordinatePoint(x: -15, y: -10)

 

 

- 하나의 프로퍼티에 접근자와 설정자가 모두 모여있고, 해당 프로퍼티가 어떤 역할을 하는지 좀 더 명확하게 표현 가능

- 인스턴스를 사용하는 입장에서도 마치 저장 프로퍼티인 것처럼 편하게 사용 가능

 

- 설정자의 매개변수로 원하는 이름을 소괄호 안에 명시해주면 set메서드 내부에서 전달받은 인자 사용 가능

- newValue로 매개변수 이름을 대신할 수 있음, 이 경우에는 매개변수 따로 표기 X

- 접근자 내부의 코드가 단 한 줄이고, 그 결괏값의 타입이 프로퍼티의 타입과 같다면 return 키워드를 생략해도
그 결괏값이 접근자의 반환 값이 됨

- 읽기 전용으로 연산 프로퍼티를 구현하려면 get 메서드만 사용

 

 

 

프로퍼티 감시자(Property Observers)


- 프로퍼티의 값이 변경됨에 따라 적절한 작업을 취할 수 있음

- 프로퍼티의 값이 새로 할당될 때마다 호출

- 프로퍼티를 재정의해 상속받은 저장 프로퍼티 또는 연산 프로퍼티에도 적용 가능

 

※ 상속받지 않은 연산 프로퍼티에는 프로퍼티 감시자를 사용할 필요가 없으며 할 수도 없음

 

- willSet 메서드 : 프로퍼티의 값이 변경되기 직전에 호출하는 메서드

- didSet 메서드 : 프로퍼티의 값이 변경된 직후 호출하는 메서드

- willSet 메서드와 didSet 메서드에는 매개변수가 하나씩 보유, willSet 메서드에 전달되는 인자는 프로퍼티가 변경될 값, 
didSet 메서드에 전달되는 전달인자는 프로퍼티가 변경되기 전의 값

 

- 매개변수의 이름을 따로 지정하지 않으면 willSet메서드에는 newValue, didSet메서드에는 oldValue로 자동 지정

- 매개변수의 이름을 따로 지정하고 싶으면 willSet이나 didSet 다음에 소괄호로 감싸고 이름 작성

 

class Account{
	var credit: Int = 0{
    	willSet{
        	print("잔액이 \(credit)원에서 \(newValue)원으로 변경될 예정입니다.")
        }
    	didSet{
        	print("잔액이 \(oldValue)원에서 \(credit)원으로 변경되었습니다.")
        }
    }
}

let myAccount: Account = Account()

myAccount.credit = 1000

// 잔액이 0원에서 1000원으로 변경될 예정입니다.
// 잔액 0원에서 1000원으로 변경되었습니다.

 

- 클래스를 상속받았다면 기존의 연산 프로퍼티를 재정의하여 프로퍼티 감시자를 구현할 수 있음

- 연산 프로퍼티를 재정의해도 기존의 연산 프로퍼티는 기능은 동작

※ 만약 프로퍼티 감시자가 있는 프로퍼티를 함수의 입출력 매개변수의 전달인자로 전달한다면 항상 willSet과 didSet 감시자 호출

 

 

 

 

전역변수와 지역변수


- 연산 프로퍼티와 프로퍼티 감시자는 전역변수와 지역변수 모두에 사용 가능

→ 프로퍼티에 한정하지 않고, 전역에서 쓸 수 있는 변수와 상수에도 두 기능 사용 가능

- 전역변수또는 지역변수는 저장변수라고 함

- 저장변수 : 저장 프로퍼티처럼 저장하는 역할

- 전역변수 또는 전역상수는 지연 저장 프로퍼티처럼 처음 접근할 때 최초로 연산이 이루어짐

- lazy 키워드를 사용하여 연산을 늦출 필요 X

- 지역변수 및 지역상수는 절대로 지연 연산되지 않음

 

var wonInPocket: Int = 2000{
	willSet{
    	print("주머니의 돈이 \(wonInPocket)원에서 \(newValue)원으로 변경될 예정입니다.")
    }
	didSet{
    	print("주머니의 돈이\(oldValue)원에서 \(wonInPocket)원으로 변경되었습니다.")
    }
}

var dollarInPocket: Double{
	get{
    	return Double(wonInPocket)
    }
    set{
    	wonInPocket = Int(newValue * 1000.0)
        print("주머니의 달러를 \(newValue)로 변경 중입니다.")
    }
}

dollarInPocket = 3.5

// 주머니의 돈이 2000원에서 3500원으로 변경될 예정입니다.
// 주머니의 돈이 2000원에서 3500원으로 변경되었습니다.
// 주머니의 달러를 3.5달러로 변경 중입니다.

 

 

 

 

타입 프로퍼티


- 각각의 인스턴스가 아닌 타입 자체에 속하는 프로퍼티

- 타입 자체에 영향을 미침

- 인스턴스 생성 여부와 상관없이 프로퍼티의 값은 하나임

- 타입 프로퍼티의 두 가지 종류

  1. 저장 타입 프로퍼티 : 변수와 상수로 선언 가능
  2. 연산 타입 프로퍼티 : 변수로만 선언 가능, 반드시 초깃값 설정

- 다중 스레드 환경이라도 단 한 번만 초기화된다는 보장을 받음

- 지연 연산된다고 해서 lazy 키워드 사용할 필요 없음

- 타입 프로퍼티를 타입 상수로도 사용 가능

 

class Account{
	static let dollarExchangeRate: Double = 1000.0
    
    var credit: Int = 0
    var dollarValue: Double{
    	get{
        	return Double(credit)
        }
        set{
        	credit = Int(newValue * Account.dollarExchangeRate)
            print("잔액을 \(newValue)달러로 변경중입니다.")
        }
    }
}

 

 

 


키 경로


- 프로퍼티도 값을 바로 꺼내오는 것이 아니라 어떤 프로퍼티의 위치만 참조하도록 할 수 있음 → 키 경로(keyPath) 활용

- 키 경로를 사용하여 간접적으로 특정 타입의 어떤 프로퍼티 값을 가리켜야 할지 미리 정해두고 사용

- 키 경로의 구성

\타입이름.경로.경로.경로

 

keyPath 서브크립트와 키 경로 활용

 

 

- 키 경로를 잘 활용하면 타입 간의 의존도를 낮추는데 많은 도움을 줌

※ 키 경로는 타입 외부로 공개된 인스턴스 프로퍼티 혹은 서브 스크립트에 한해 표현 가능

- Swift 5.2 버전부터 (SomeType) -> Value 타입의 클로저를 키 경로 표현으로 대체 사용 가능

 

클로저를 대체할 수 있는 키 경로 표현

 

 

메서드


- 특정 타입에 관련된 함수

- 클래스, 구조체, 열거형 등은 실행하는 기능을 캡슐화한 인스턴스 메서드를 정의할 수 있음

- 기존의 프로그래밍 언어에서의 클래스 메서드와 유사

 

 

 

인스턴스 메서드


- 특정 타입의 인스턴스에 속한 함수

- 인스턴스의 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등 인스턴스와 관련된 기능을 실행

- 자신의 프로퍼티 값을 수정할 때 클래스의 인스턴스 메서드는 크게 신경 쓸 필요 없지만, 구조체나 열거형 등은 값 타입이므로
메서드 앞에 mutating 키워드를 붙여 해당 메서드가 인스턴스 내부의 값을 변경한다는 것을 명시해야 함

mutating 키워드의 사용

 

 

 

self 프로퍼티


- 모든 인스턴스는 암시적으로 생성된 self 프로퍼티를 가짐

- 자바의 this와 비슷한 개념

- 인스턴스를 더 명확히 지칭하고 싶을 때 사용

- 값 타입 인스턴스 자체의 값을 치환할 수 있음(구조체나 열거형일 경우)

 

self 프로퍼티와 mutating 키워드

 

 


callAsFunction


- 인스턴스를 함수처럼 호출할 수 있게 하는 키워드

- 매개변수와 반환타입만 다르다면 개수에 제한 없이 원하는 만큼 만들 수 있음

- mutating 키워드, throws와 rethrows도 함께 사용 가능

- 메서드를 호출하는 것 외에 함수 표현으로는 사용 불가

 

Puppy 구조체에 callAsFunction 메서드 구현

 

 

 

 

타입 메서드


- 타입 자체에 호출이 가능한 메서드

- 메서드 앞에 static 키워드를 사용하여 타입 메서드임을 나타내 줌

- 클래스의 타입 메서드는 static 키워드와 class 키워드로 사용 가능,
static으로 정의하면 상속 후 메서드 재정의가 불가, class로 정의하면 상속 후 메서드 재정의가 가능

 

클래스 타입의 메서드

 

- 인스턴스 메서드에서 self가 인스턴스를 가리킨다면, 타입 메서드의 self는 타입을 가리킴

 

타입 프로퍼티와 타입 메서드의 사용

728x90

'iOS > Swift' 카테고리의 다른 글

[Swift] 서브스크립트  (2) 2022.09.22
[Swift] print(_:separator:terminator:)  (0) 2022.09.21
[Swift] 구조체와 클래스  (0) 2022.09.16
[Swift] 모나드  (0) 2022.09.16
[Swift] 옵셔널(Optional)  (0) 2022.09.15
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.