초기화 (Initialization)
- 클래스, 구조체, 열거형 인스턴스를 사용하기 위해 준비 작업을 하는 단계
- 각 저장 프로퍼티의 초기 값을 설정 →initializer를 정의 하는 것으로 구현
저장 프로퍼티를 위한 초기값 설정
인스턴스의 저장 프로퍼티는 사용하기 전 반드시 특정 값으로 초기화 돼야 함 (기본 값으로 설정/특정 값으로 설정 가능)
NOTE
initializer에서 저장 프로퍼티에 값을 직접 설정하면 프로퍼티 옵저버가 호출되지 않고 값 할당이 수행
이니셜라이저
특정 타입의 인스턴스 생성 (이니셜라이저의 가장 간단한 형태_ 파라미터 없이 init 키워드 사용)
init() {
// perform some initialization here
}
기본 프로퍼티
프로퍼티 선언과 동시에 값을 할당, 이 값을 초기 값으로 사용 가능.
NOTE
항상 같은 초기 값을 갖는다면 기본 프로퍼티를 사용하는 것이 좋음
프로퍼티에 타입을 선언하지 않아도 컴파일러는 초기 값을 참조해서 타입을 추론할 수 있음
이 기본값은 상속시 함께 상속
커스터마이징 초기화
초기화 프로세스를 입력 값과 옵셔널 프로퍼티 타입/상수 값을 할당, 커스터마이징 가능
초기화 파라미터
초기화 파라미터를 정의해 사용할 수 있음
파라미터 이름과 인자 레이블
메소드 파라미터와 초기화 파라미터 모두 파라미터 이름과 인자 레이블을 갖지만, 이니셜라이저는 특정 메소드에서 지정하는 메소드 이름을 지정하지 않고 이니셜라이저 식별자로 파라미터를 사용
💡
모든 파라미터는 인자 레이블을 갖고 사용자가 지정하지 않을 시, Swift가 자동으로 하나를 할당해 제공
인자 레이블이 없는 이니셜라이저 파라미터
코드를 작성할 때 인자 레이블을 생략하는 것이 더 명료한 경우 ' _ 기호' 를 사용해 이니셜라이저에서 인자 레이블을 생략
옵셔널 프로퍼티 타입
프로퍼티 최초 값이 없고 나중에 추가될 수 있는 값을 옵셔널로 선언해 사용 (옵셔널 프로퍼티는 자동으로 nill로 초기화)
초기화 중에 상수 프로퍼티 할당
이니셜라이져에서 상수 프로퍼티에 값을 할당하는 것 가능
NOTE
클래스 인스턴스에서 상수 프로퍼티는 초기화 중 그 클래스 안에서만 변경이 가능하고 서브클래스에서는 변경이 불가능
프로퍼티를 let으로 선언해서 이 프로퍼티는 처음에 초기화 되면 변경되지 않는 프로퍼티라는 것을 표현
기본 이니셜라이저
만약 모든 프로퍼티의 초기값이 설정돼 있고, 하나의 초기자도 정의하지 않았다면 Swift는 모든 프로퍼티를 기본 값으로 초기화 하는 기본 초기자를 제공
구조체 타입을 위한 멤버쪽 이니셜라이저 (프로퍼티의 이름을 매개변수로 갖는 이니셜라이저)
기본 이니셜라이저와 다르게 맴버쪽 이니셜라이저는 프로퍼티가 기본 값이 없어도 커스텀 이니셜라이저를 정의하지 않았다면 멤버쪽 이니셜라이저를 제공
값 타입을 위한 이니셜라이저 위임
- 이니셜라이저 위임: 이니셜라이저에서 다른 이니셜라이저를 호출
- 값 타입(struct, enum)과 클래스 타입(class)간 이니셜라이저 위임 동작 다름
- 값 타입은 상속을 지원하지 않아 이니셜라이저를 자기 자신의 다른 이니셜라이저에만 사용
- 클래스 타입은 상속이 가능하기 때문에 superclass의 이니셜라이저를 subclass에서 호출 가능
- 상속 받은 모든 프로퍼티의 초기화는 책임은 이니셜라이저에 있음
- 커스텀 이니셜라이저 선언시 기본 이니셜라이저 혹은 멤버쪽 이니셜라이저를 사용할 수 없음
- 위의 제약으로 이니셜라이저의 복잡성을 낮추고 이니셜라이저가 의도하지 않게 사용되는 것을 방지
NOTE
커스텀 이니셜라이저를 사용하면서 기본 이니셜라이저와 맴버쪽 이니셜라이저도 사용하고 싶다면 커스텀 이니셜라이저를 오리지널 클래스에서 구현하지 않고 익스텐션(extension)에서 구현
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
클래스 상속과 초기화
모든 클래스의 저장 프로퍼티와 superclass로부터 상속받은 모든 프로퍼티는 초기화 단계에서 반드시 초기값 할당 (Swift에서는 클래스 타입에서 모든 프로퍼티가 초기 값을 갖는 것을 보장하기 위해 2가지 방법 지원)
지정 초기자와 편리한 초기자
- 지정 초기자: 클래스의 주 초기자
- 클래스의 모든 프로퍼티를 초기화, 클래스 타입은 반드시 한개 이상의 지정 초기자 존재필수
- 편리한 초기자: 초기화 단계에서 미리 지정된 값을 사용해 최소한의 입력으로 초기화할 수 있도록 하는 초기자
- 편리한 초기자 내에서 반드시 지정 초기자가 호출
지정 초기자와 편리한 초기자의 문법
//지정 초기자 문법
init(parameters) {
statements
}
//편리한 초기자 문법
convenience init(parameters) {
statements
}
자동 초기자 인스턴스
초기화 과정 중에 실패할 가능성이 있는 초기자를 init뒤에 물음표(?)를 사용해 실패가 가능한 초기자라고 표시
NOTE
초기자는 이름이 따로 있는 것이 아니라 파라미터로 구분하기 때문에 실패 가능한 초기자와 실패 불가능한 초기자를 같은 파라미터 타입과 이름으로 동시에 사용 불가능
실패 가능한 초기자는 반환값으로 옵셔널 값을 생성 (초기화에 실패하는 부분에서 nil을 반환하는 코드를 작성해 초기화가 실패했다는 것을 나타낼 수 있음)
NOTE
엄밀히 말하면 초기자 init은 값을 반환하지 않음. 비록 nil을 반환하는 return nil 코드에는 사용하지만 init이 성공하는 경우 return 키워드를 사용하지 않음
필수 초기자
- 모든 서브클래스에서 반드시 구현해야 하는 초기자, required 키워드 붙임
- 필수초기자를 상속받은 서브클래스에서도 반드시 required 키워드를 붙여서 다른 서브클래스에게도 이 초기자는 필수 초기자라는 것을 알려야 함
클로저나 함수를 이용해 기본 프로퍼티 값 설정하기
기본 값 설정이 단순히 값을 할당하는 것이 아니라 다소 복잡한 계산을 필요하다면 클로저나 함수를 이용해 값을 초기화 하는데 이용할 수 있음
초기화 해지 (Deinitialization)
생성자와 반대로 클래스 인스턴스가 소멸되기 직전에 호출
deinit {
// perform the deinitialization**
}
- 클래스당 오직 하나만 선언할 수 있고 파라미터를 받을 수 없음
- 소멸자는 자동으로 호출되고 수동으로 호출할 수 없음
- Superclass의 소멸자는 Subclass에서 소멸자를 선언하지 않아도 자동으로 호출됨
초기화의 사용
class Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
}
var playerOne: Player? = Player(coins: 100)
print("A new player has joined the game with \\(playerOne!.coinsInPurse) coins")
// Prints "A new player has joined the game with 100 coins"
// 사용자는 100 코인을 갖고 시작합니다.
print("There are now \\(Bank.coinsInBank) coins left in the bank")
// Prints "There are now 9900 coins left in the bank"
// 현 시점에 은행은 9900의 코인을 소유하고 있습니다.
playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \\(playerOne!.coinsInPurse) coins")
// Prints "PlayerOne won 2000 coins & now has 2100 coins"
// 사용자가 게임에 이겨 2000코인을 받아 처음에 갖고 있던 100 코인과 더불어 현재 총 2100 코인을 소유하게 됩니다.
print("The bank now only has \\(Bank.coinsInBank) coins left")
// Prints "The bank now only has 7900 coins left"
// 사용자에게 2100 코인을 나눠준 은행에는 현재 7900 코인이 남았습니다.
playerOne = nil
print("PlayerOne has left the game")
// Prints "PlayerOne has left the game"
// 사용자가 게임에서 나갔습니다.
print("The bank now has \\(Bank.coinsInBank) coins")
// Prints "The bank now has 10000 coins"
'⌨️ Language > swift' 카테고리의 다른 글
[Swift] 에러 처리 (0) | 2024.03.28 |
---|---|
[Swift] 옵셔널 체이닝 (0) | 2024.03.26 |
[Swift] 상속 (0) | 2024.03.22 |
[Swift] 서브스크립트 (0) | 2024.03.22 |
[Swift] 메서드 (0) | 2024.03.21 |
댓글