[야곰] Swift 개념정리 - 상속과 이니셜라이저

Judy·2022년 3월 20일
0

Swift 공부

목록 보기
10/11

상속

1. 정의

  • 상속은 클래스, 프로토콜에서 가능하고 열거형, 구조체는 불가능
  • 다중상속 ❌, 단일상속만 가능
class 이름: 상속받을 클래스 이름 {
	// 구현 및 재정의
}

클래스 이름 뒤에 [ : ] 키워드 이후 상속받고자 하는 클래스 이름을 쓰면 된다.

2. 상속과 재정의

class Person {
	var name: String = ""
    func selfIntroduce() { // 재정의 가능
    	print("저는 \(name)입니다.")
    }
    final func sayHello() {	// 재정의 불가
    	print("Hello")
    }
    static func typeMethod() {	// 제정의 불가 타입 메서드
    	print("Type Method - static")
    }
    class func classMethod() {	// 재정의 가능 타입 메서드
   		print("Type Method - class")
    }
    final class func finalClassMethod() { // 재정의 불가
    	print("Type Method - final class")
    }
}

class Student: Person{
	var major: String = ""
    override func selfIntroduce() {
    	print(" 저는 \(name)이고 전공은 \(major)입니다.")
    }
    override class func classMethod() {
    	print("overriden class method")
    }
}

  • final 키워드 - override 불가 = 자식 클래스가 재정의 불가
  • static 메서드 - 재정의 불가 타입 메서드
  • class 메서드 - 재정의 가능 타입 메서드
  • class 메서드라도 final 키워드가 붙으면 재정의 불가
    final class = static

Student는 Person을 상속받아서 자동으로 "name" 프로퍼티를 가진다.

저장 프로퍼티는 재정의가 불가능하다.

부모 클래스의 함수를 호출하고 싶으면 super 키워드를 이용해 [ super.selfIntroduce() ]로 불러올 수 있다.


3. 상속의 결과

let human: Person = Person()
let jane: Student = Student()

human.name = "saram"
jane.name = "jane"
jane.major = "iOS"

human.selfIntroduce()
// 저는 saram입니다.
jane.selfIntroduce()
// 저는 jane이고 전공은 iOS입니다.
Person.classMethod()
// ype Method - class
Student.classMethod()
// overriden class method
Student.typeMethod()
// Type Method - static

Student는 "major" 프로퍼티를 추가해 이용할 수 있지만, 부모 클래스에는 존재하지 않는다.

재정의한 타입 메서드들은 부모 클래스의 타입 메서드와 다르게 동작하고. 재정의하지 않은 메서드는 부모 클래스와 동일한 기능을 한다.



이니셜라이저

1. 인스턴스의 초기값


모든 타입의 인스턴스는 초기화될 때 프로퍼티는 유효한 값을 가져야 한다.

타입 정의 시 프로퍼티의 기본값을 할당해두면 인스턴스가 초기화 될 때 초기값으로 가지게 된다.

class Person {
	var name: String = "unknown"
    var age: Int = 0
    var nickName: String = "nick"
}

let jane: Person = Person()

jane.name = "jane"
jame.age = 30
jane.nickName = "j"

인스턴스 초기화 후 생성된 인스턴스의 프로퍼티를 각각 변경하여 원하는 값을 할당할 수 있다.

2. 이니셜라이저(init)


마땅히 초기화할 값이 없거나 프로퍼티 기본값을 지정하기 어려운 경우에는 ` init`을 통해 초기값을 전달받을 수 있다.
class PersonA {
	var name: String 
    var age: Int
    var nickName: String
    
    init(name: String, age: Int, nickName: Stirng) {
    	self.name = name
        self.age = age
        self.nickName = nickName
    }
}

let jane: PersonA = PersonA(name: "jane", age: 30, nickName: "j")

1) 옵셔널을 이용한 이니셜라이저


인스턴스 사용에 반드시 필요한 프로퍼티가 아니거나 ㅊ초기값이 필요하지 않은 프로퍼티가 있을 경우에는 해당 프로퍼티를 **옵셔널** [** ?** ] 로 정의하면 된다.
class PersonB {
	var name: String 
    var age: Int
    var nickName: String?
    
    init(name: String, age: Int, nickName: Stirng) {
    	self.name = name
        self.age = age
        self.nickName = nickName
    }
    init(name: String, age: Int) {
    	self.name = name
        self.age = age
    }
}

let jane: PersonB = PersonB(name: "jane", age: 30, nickName: "j")
let hana: PersonB = PersonB(name: "hana", age: 10)

여러 개의 이니셜라이저 구현이 가능하고, 옵셔널로 정의된 프로퍼티는 포함하지 않아도 된다.
convenience init(name: String, age: Int, nickName: Stirng) { 
	self.init(name: name, age: age)
     self.nickName = nickName
 }

코드의 중복을 줄이기 위해 `convenience` 키워드를 붙여 이미 구현한 자신의 이니셜라이즈를 호출할 수도 있다.



class Pet{
	var name: String 
    var owner: PersonB!
 
    init(name: String) {
    	self.name = name
    }
    func goOut(){
    	print("\(name)\(owner.name)과 함께 산책을 갑니다.")
    }
}

let puppy: Pet = Pet(name: "happy")

puppy.goOut()	// owner가 정의되지 않아 에러 ⚠️
puppy.owner = jane
puppy.goOut()	// happy거 jane과 함께 산책을 갑니다.

암시적 추출 옵셔널 [ ! ] 은 인스턴스가 생성될 때 초기값이 필요하진 않거나 할당할 수 없지만, 인스턴스 사용 시엔 반드시 필요한 경우에 사용된다.


2) 실패가능한 이니셜라이저


인스턴스 생성 시 전달되는 초기값이 잘못되었을 경우 이니셜라이저가 실패할 수도 있다.

이니셜라이저를 실패하면 nil을 반환하게 되므로 실패 가능한 이니셜라이저로 init? 를 사용할 수 있다.

class PersonC {
	var name: String 
    var age: Int
    var nickName: String?
   
    init?(name: String, age: Int) {
    	if name.characters.count == 0{
        	return nil
        }
    	self.name = name
        self.age = age
    }
}

let jane: PersonC? = PersonC(name: "jane", age: 30)
let hana: PersonC? = PersonC(name: "", age: 10)	// nil

옵셔널 타입의 이니셜라이저를 사용하면 인스턴스 역시 옵셔널 타입으로 선언해야 한다.

3. 디이니셜라이저 (deinit)


인스턴스가 생성될 때 이니셜라이저가 호출된다면, 인스턴스가 메모리에서 해제될 때는 디이니셜라이저가 호출된다.

인스턴스가 해제되는 시점에 동작을 구현할 수 있다.

class PetOwner{
	var name: String
    var petName: Pet
    var child: PersonC
    init(name: String, pet: String, child: String){
    	self.name = name
        self.petName = pet
        self.child = child
    }
    
    deinit{
    	print("\(name)이 \(child)에게 \(pet)을 인도합니다.)
    	self.pet.owner = child    
    }
}

let jane: PetOwner = PetOwner(name: "jane", pet: "happy", child: "hana")
jane = nil	// jane 인스턴스가 메모리에서 해제된다
// jane이 hana에게 happy를 인도합니다.
  • 직접 호출 불가능
  • 클래스 타입에만 구현 가능





[ 참고자료 ][Swift - Initialization](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html)
Swift - Deinitialization

profile
iOS Developer

0개의 댓글