Initializer

박인준·2019년 12월 5일
0

Swift

목록 보기
9/21

Initializer

  • Swift 의 객체는 사용하기 전 모든 저장 프로퍼티에 대해 초기화 필수
  • 다음 3 가지 중 하나를 택해 초기화
    - 초깃값 지정
    - 옵셔널 타입 - nil 값으로 초기화
    - 초깃값이 없고, 옵셔널 타입이 아닌 프로퍼티에 대해서는 초기화 메서드에서 설정

예제

class Circle {
  var desc: String?
  var radius: Int = 20
  var xCoordinate: Int
  var yCoordinate: Int
  
  init() {
    xCoordinate = 5
    yCoordinate = 10
  }
  
  init(xCoordinate: Int, yCoordinate: Int) {
    self.xCoordinate = xCoordinate
    self.yCoordinate = yCoordinate
  }
}

let circle1 = Circle()
let circle2 = Circle(xCoordinate: 10, yCoordinate: 5)

Designated Initializer (지정생성자)

  • 클래스에 반드시 1개 이상 필요
  • 초기화가 필요한 모든 프로퍼티를 단독으로 초기화 가능한 Initializer
  • 위에서 사용한 init(), init(height: Int, xPosition: Int) 가 여기에 해당
  • 초기화 과정에서 반드시 한 번은 호출

Convenience Initializer (편의생성자)

  • 단독으로 모두 초기화할 수 없고 일부만 처리한 뒤 다른 생성자에게 나머지 부분 위임
  • 중복되는 초기화 코드를 줄이기 위해 사용
    => 생성자 안에서 생성자를 호출할 수 있는 것은 convenience만 가능!

@최종적으로는 designated Initializer가 호출되어야 함

예제

class Rectangle {
  var width: Int
  var height: Int
  var xPosition: Int
  var yPosition: Int
  var cornerRadius: Int
  
  init() {
    // designated init
    width = 20
    height = 20
    xPosition = 10
    yPosition = 10
    cornerRadius = 5
  }
  
  init(width: Int, height: Int, xPosition: Int, yPosition: Int, cornerRadius: Int) {
    // designated init
    self.width = width
    self.height = height
    self.xPosition = xPosition
    self.yPosition = yPosition
    self.cornerRadius = cornerRadius
    
    // self.init()  // designated init can't call designated init
  }
  
  convenience init(xPosition: Int) {
    // convenience init -> designated init -> overwrite
    self.init()
    self.xPosition = xPosition
  }
  
  convenience init(width: Int, height: Int, cornerRadius: Int) {
    // convenience init -> designated init
    self.init(width: width, height: height, xPosition: 10, yPosition: 30, cornerRadius: cornerRadius)
  }

  convenience init(cornerRadius: Int) {
    // convenience init -> convenience init
    self.init(width: 20, height: 20, cornerRadius: cornerRadius)
  }
}

let rectangle1 = Rectangle(xPosition: 20)
let rectangle2 = Rectangle(cornerRadius: 5)
let rectangle3 = Rectangle(width: 10, height: 10, xPosition: 10, yPosition: 5, cornerRadius: 3)

Failable Initializer

  • 인스턴스 생성시 특정 조건을 만족하지 않으면 객체를 생성하지 않는 것
  • 생성이 되면 옵셔널 타입을 반환하게 되며, 생성 실패시에는 nil 반환
class Person {
  let name: String
  let age: Int
  
  init?(name: String, age: Int) {     //-> init? ; failabe initializer
    guard age > 0 else { return nil }
    self.name = name
    self.age = age
  }
}

//Failable Initializer

if let person = Person(name: "James", age: 20) {
  person
}

if let person = Person(name: "James", age: -5) {
  person
} else {
  "Failed"
}

Super Class Initializing

  • 서브 클래스는 자기 자신 이외에 수퍼 클래스의 저장 프로퍼티까지 초기화 해야 함
  • 서브 클래스는 수퍼 클래스의 지정 생성자(Designated Initializer) 호출 필요 (Convenience는 호출 불가)
  • 수퍼 클래스의 지정 생성자가 기본 init 함수 하나만 있을 경우는
    별도로 작성하지 않아도 자동으로 super.init() 메서드 호출
  • 생성자가 여러 개인 경우, 어떤 초기화 메서드를 선택해야 할지 알 수 없으므로 선택해주지 않으면 오류
    이 때는 서브 클래스에서 수퍼 클래스의 생성자를 명시적으로 선택해주어야 함.
    편의 생성자(Convenience Initializer)는 무관

예제

class Base {
  var someProperty: String
  
  init() {
    someProperty = "someProperty"
  }
  
//  init(_ value: String) {
//    self.someProperty = "someProperty"
//  }
  
  convenience init(someProperty: String) {
    self.init()
    self.someProperty = someProperty
  }
}

class Rectangle: Base {
  var width: Int
  var height: Int
  
  override init() {
    width = 10
    height = 5
    
//    super.init()   // 수퍼 클래스의 지정 생성자가 기본 생성자 하나만 있을 경우 자동 호출
//    super.init(someProperty: "생성자 내에서 수퍼 클래스의 편의 생성자 호출 시 오류")
  }
  
  init(width: Int, height: Int) {
    self.width = width
    self.height = height
  }
}

-> initializer는 자동호출되더라도 선언하는 연습을 하는 것을 추천

@덮어쓰기 초기화(override init)도 가능함

class Human {
  var name: String
  
  init() {
    self.name = "홍길동"
  }
  init(name: String) {
    self.name = name
  }
}


class Student: Human {
  var school: String
  
  override init() {
    self.school = "University"
    
    // 두 개의 지정 생성자 중 하나 호출
    super.init()
//    super.init(name: "이순신")
  }
  
  init(school: String) {
    self.school = school
    super.init()
  }
  
  
  // 수퍼 클래스의 지정 생성자 오버라이드와 편의 생성자 기능 동시 사용 가능
  convenience override init(name: String) {
    self.init(school: "Univ")
    self.name = name
  }
}

let student1 = Student()
let student2 = Student(name: "철수")
let student3 = Student(school: "High School")

Initializer 의 다른 특징들

  • 초기화 이전에 프로퍼티 사용 불가
  • 초기화 이전 단계에서 인스턴스 메서드 호출 불가
  • 다른 메서드 호출 중 초기화 되지 않은 프로퍼티를 사용할 수도 있기 때문에 컴파일 에러 발생

@다양한 initializer

/*
 Extension Initializer
 - Extension에서는 Convenience Initializer는 추가할 수 있어도
   Designated Initializer는 할 수 없음
 */

class Rectangle {
  var height: Int
  var xPosition: Int
  
  init(height: Int, xPosition: Int) {
    self.height = height
    self.xPosition = xPosition
  }
}

extension Rectangle {
  convenience init(height: Int) {
    self.init(height: height, xPosition: 10)
  }
  
  // Extension 내에서는 Convenience Initializer 만 가능
//  init(xPosition: Int) {
//    self.height = 10
//    self.xPosition = xPosition
//  }
}

let rect1 = Rectangle(height: 10, xPosition: 20)
let rect2 = Rectangle(height: 10)


/*
 Required Initializer
 - 상속받은 클래스에서 반드시 작성해주어야 하는 초기화 메서드가 있을 때 required 키워드 사용
 - 이 경우 서브 클래스에서는 해당 초기화 메서드를 반드시 작성해주어야 하며, override 키워드 생략 가능
 */

class Animal {
  let name: String
  let age: Int

  init(age: Int) {
    self.age = age
    self.name = "Tori"
  }
  required init(name: String) {
    self.name = name
    age = 3
  }
}

class Dog: Animal {
  let type: String
  
  init(type: String) {
    self.type = type
    super.init(name: "Tori")
  }
  
  required init(name: String) {
    self.type = "Poodle"
    super.init(name: name)
  }
}

let dog1 = Dog(type: "Poodle")
let dog2 = Dog(name: "Tori")


/*
 Deinitializer
 - 할당된 객체가 해제될 때 deinit 메서드 호출
 */

class SomeClass {
  init() {
    print("Initialized")
  }
  deinit {
    // 객체 메모리 해제 시 동작할 코드
    print("Deinitialized")
  }
}


func someFunction() {
  let someClass = SomeClass()
  someClass    // 함수 종료와 함께 해제
}
someFunction()

위의 예제는 수업중 강사님께서 제공해주신 예로 실제 project에서 어떻게 사용하는지는 반드시 연습이 필요함!!

profile
iOS 개발자가 되기 위해

0개의 댓글