Class - Initialization

Eli·2021년 2월 7일
1

Swift

목록 보기
11/17
post-thumbnail

초기화는 클래스, 구조체, 열거형 인스턴스를 사용 준비하는 단계로 각 프로퍼티의 초기 값을 설정한다.
이전에는 단순히 선언과 함께 초기화를 해주면서 init 코드를 보면 좀 두려움이 있었던 것 같은데,
규칙이나 순서가 몇가지 있다는 것을 이해하는 좋은 시간이었다.

Syntax

class SomeClass {
		init() {
		}
}

Default Property Values

프로퍼티 선언과 동시에 값을 지정해 초기값으로 사용하고 init에서 지정하지 않을 수 있습니다.

struct SomeStruct {
		var someProperty = 32.0
		
		//구현하지 않아도 됨
		init(property: Double) {
				self.someProperty = property
		}
}

Customizing initialization

초기화 인자값 및 할당을 커스터마이징 할 수 있다.

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)

Optional Property types

프로퍼티가 옵셔널 타입이라면 init과정에서 별도로 값을 할당하지 않는다면 자동적으로 nil이 할당되어있다.
var optionalValue: Int? = nil //요거 할 필요 없다는 얘기

Assigning Constants Properties During Initialization

초기화 중에 상수 프로퍼티에 값을 할당 할 수 있다.

class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// Prints "How about beets?"

Default Initializers(class/struct)

  1. 모든 초기값이 설정 돼 있음.
  2. 커스터마이징 초기자가 없음
    위의 경우에는 Swift에서 기본 초기자를 자동적으로 제공해 간단하게 초기화 할 수 있다.
class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()

Initializer Delegation for Value Types

이니셜라이저에서 다른 이니셜라이저를 호출한다.
값을 바로 할당해 초기화 하는 것.

아래와 같이 쓸 수 있다.

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

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과 size의 할당을 위임한다는 의미
        //말이 어려워서 그렇지만... 그냥 다른 init 호출해서 쓰는게 가능하다는 걸로 이해
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))

Class Inheritance and Initialization

Class에는 상속이란게 있어서 Super Class 와의 관계가 생기면서 좀 복잡해지는 것 같다.
이제부터 init의 규칙? 같은 내용이다. 지루하지만 한번 이해하고 알아두면 좋은듯 하다.

모든 클래스의 프로퍼티와 슈퍼클래스의 모든 프로퍼티는 초기에 값이 설정되어야하며, 2가지 방법을 제공한다. (Class 내의 init끼리의 규칙)

  • Designated Initializers and Convenience Initializers
    • Designated Initializers는 클래스의 이니셜라이즈중 주된 구문이며, 모든 프로퍼티를 초기화 합니다. 클래스는 한개 이상의 Designated Initializers가 있어야 합니다.
    • Convenience Initializer는 미리 지정된 값을 이용해서 최소한 입력으로 초기화 할 수 있도록 해주는 초기화. 편리한 초기자에서는 반드시 다른 Initializer를 호출해야합니다.
//Designated Initializer
init(params) {
	//초기화
}

//Convenience Initializer
convenience init(params) {
	//초기화
}
  • Initializer Delegation for Class Types
    위임을 위해 Designated Initializer와 Convenience Initializer의 관계를 단순히 하기위해 다음과 같이 3개의 규칙이 있습니다.
  1. Designated Initializer는 반드시 superclass의 Designated Initializer를 초기화해야한다.
  2. Convenience Initializer는 반드시 다른 초기자를 호출해야한다.
  3. Convenience Initializer는 최종적으로 Designated Initializer를 호출해야한다.

그림은 복잡하지만 글이 이해가 됐다면 쉽게 보인다.

  • Two-Phase Initialization (init 내부의 규칙)
    Swift에서 초기화는 2단계의 과정을 통해 초기화됩니다.

단계 1

  1. initializer 호출
  2. 해당 sub-class의 모든 프로퍼티를 초기화 체크 후 super-class 초기화 진행
  3. 최상단 클래스의 모든 프로퍼티 값 확인 후, 초기화 완료

단계 2

  1. 최상단 클래스의 init이 끝난 이후부터 self를 사용이 가능.
  2. 그 이후 하위 클래스의 designated init
  3. 그 이후 하위 클래스의 convenience init 순으로 self 사용이 가능

swift 는 위 2가지 과정을 안전하게 사용하도록 4가지의 규칙을 제공. 규칙을 지키지 않으면 컴파일 에러

  1. Designated init에서는 현재 클래스의 프로퍼티가 지정되어 있어야한다.
  2. Designated init에서는 상속받은 프로퍼티에 할당하기 이전에 superclass init 필요
  3. Convenience init에서는 모든 프로퍼티에 할당하기 이전에 다른 initializer을 수행해야한다. (2번과 비슷한 규칙으로 상위의 init 먼저 수행)
  4. 단계 1 과정 전에는 어떠한 메소드나 프로퍼티를 접근하여 가져오는게 불가능하다.
  • Initializer Inheritance and Overriding
    기본적으로 sub-class에서 super-class init 상속을 하진 않는다.
    상속관계가 복잡해질 때 잘못 초기화되는 것을 막기 위함.

안전하고 특정한 상황에서 오버라이드가 가능한데 아래의 예시에서 가능하다.

class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
		//정의 시점에 모든 프로퍼티가 할당될 값이 지정된다면 자동 initializer가 생성된다.
}

class Bicycle: Vehicle {
    override init() {
        super.init()
        numberOfWheels = 2
    }
}

let bicycle = Bicycle()

Failable Initializers

  • Propagation of Initialization Failure

    init? 과 같이 구현을 하면 실패가능한 초기자가되어 nil을 리턴할 수 있게된다.

  • Overriding a Failable Initializer

    실패가능한 초기자를 override 하여 실패 불가능한 초기자로 가능

    class Document {
        var name: String?
        // this initializer creates a document with a nil name value
        init() {}
        // this initializer creates a document with a nonempty name value
        init?(name: String) {
            if name.isEmpty { return nil }
            self.name = name
        }
    }
    
    class AutomaticallyNamedDocument: Document {
        override init() {
            super.init()
            self.name = "[Untitled]"
        }
        override init(name: String) {
            super.init()
            if name.isEmpty {
                self.name = "[Untitled]"
            } else {
                self.name = name
            }
        }
    }
    • init!
      실패가능한 초기자를 강제 언래핑해 오버라이드도 가능

      		```
      		class UntitledDocument: Document {
      	  override init() {
      super.init(name: "[Untitled]")!
      }
      		}
      		```

      Required Initializers

      모든 서브클래스에서 반드시 구현해야 하는 초기자에는 아래와 같이 required 키워드를 붙여 구현 가능.

      		```
      		class SomeClass {
      required init() {

      // initializer implementation goes here
      }
      }

      		```

      #학습에 대한 내용으로 틀린 내용이 있을 수 있습니다.
      #댓글로 남겨주시면 더 좋은 게시글로 수정하도록 하겠습니다.

profile
애플을 좋아한다. 그래서 iOS 개발을 한다. @Kurly

0개의 댓글

관련 채용 정보