IOS- 15

김정현·2023년 3월 22일
0

IOS 개발공부 일지

목록 보기
15/27

클래스 상속

상속은 기반클래스를 다른 클래스에서 물려받는 것을 말한다. 부모 클래스의 메서드, 프로퍼티 등을 재정의하거나 기반클래스의 기능이나 프로퍼티를 물려받고 자신의 기능을 추가할 수 있다.

  • 클래스 이름 뒤에 콜론을 붙이고 다른 클래스 이름을 써주면 뒤에 오는 클래스의 기능을 앞의 클래스가 상속 받은 것임을 뜻한다.
class 클래스 이름: 부모클래스 이름 {
   프로퍼티와 메서드들 
}

자식 클래스는 부모 클래스의 프로퍼티와 메서드를 사용할 수 있으며 자신이 정의한 프로퍼티와 메서드도 사용 가능하다.

재정의

부모클래스로부터 물려받은 특성을 사용하지 않고 자신만의 기능으로 변경하여 사용하는 것을 재정의라고 한다.
override 키워드로 재정의가 가능하다.
만약, 재정의 후 부모 클래스의 특성을 자식 클래스에서 사용하고 싶다면 super 프로퍼티를 사용하면 된다.

override func someMethod

super.someMethod
super[index]         // 서브스크립트에서    

메서드 재정의

func speak() {               ////부모클래스에서
  print("가나다마라마사")
  }                   
  
  
  
override func speak() {      //자식클래스에서
  print("ABCDEFG")
}


override func speak() {   //자식클래스에서
  super.speak()
  print("qwer")
}    


//ABCDEFG qwer           // 맨 마지막 구문에서 출력문

프로퍼티 재정의

프로퍼티를 재정의할때는 저장 프로퍼티를 재정의할 수는 없다. 재정의하는 것은 접근자(getter), 설정자(setter), 프로퍼티 감시자(property observer)등을 재정의 하는 것이기 때문이다.

  • 조상클래스에서 읽기 전용 프로퍼티일 경우 자식 클래스에서 읽고 쓰기 가능 프로퍼티로 재정의 가능
  • 그러나 읽고 쓰기가 가능한 프로퍼티를 읽기전용으로 재정의 불가
  • 읽고 쓰기가 가능한 프로퍼티를 재정의할때 설정자만 따로 재정의 불가. 접근자와 설정자 모두 재정의해야만 함
class person {
	 var name: String =""
     var age: Int = 0
     var koreanAge: Int {        //읽기만 가능.
     	return self.age +1 
     }
     
     var introduction: String {
     	return "이름 : \(name). 나이: \(age)"
     }
}

class Student: Person {     //부모클래스 person을 상속 받음
	var grade: String = "F"
    
    override var introduction + " " + "학점 : \(self.grade)"          // 부모클래스 introduction 연산 프로퍼티를 재정의함.
    }
    
    override var koreanAge: Int {
    	get {
        	return super.koreanAge      //부모클래스 koreanAge 값을 받아옴.  // 읽고쓰기가 가능하게 변경함
       }
       
       set {
       	self.age = newValue - 1
        }
    }
}

프로퍼티 감시자 재정의

감시도 접근자와 설정자처럼 재정의할 수 있다. 조상클래스에서 정의한 프로퍼티가 연산 프로퍼티인지 저장 프로퍼티인지는 상관없다. 상수, 읽기전용 프로퍼티는 값을 설정할 수 없으므로 willSet이나 didSet 메서드를 사용 할 수 조차 없다.

  • 프로퍼티 접근자와 감시자는 동시에 재정의할 수 없다.

서브스크립트 재정의

서브스크립트도 메서드와 마찬가지로 재정의가 가능하다. 매개변수와 반환타입이 다르면 다른 서브스크립트로 취급하므로 같아야한다.

재정의방지

부모클래스를 상속받는 자식클래스에서 몇몇 특성을 재정의할 수 없도록 제한하고 싶다면 재정의를 방지하고 싶은 특성 앞에 final 키워드를 명시하면 된다.

final var.  final func. final subscript.

final class     // 클래스를 상속하거나 재정의할 수 없도록 제한한다.

지정 이니셜라이저와 편의 이니셜라이저

지정 이니셜라이저는 주요 이니셜라이저이다. 필요에 따라 부모클래스의 이니셜라이저를 호출할 수 있다. 이니셜라이저가 정의된 클래스의 모든 프로퍼티를 초기화해야하는 임무를 갖고 있다. 클래스에 반드시 하나 이상 정의한다.
조상클래스에서의 지정 이니셜라이저가 자손클래스에서도 역할을 충분히 한다면 자손클래스에서는 갖지 않을 수도 있다.

init(매개변수들) {
	초기화구문
}

편의 이니셜라이저는 초기화를 좀 더 쉽게 도와주는 역할을 한다. 지정 이니셜라이저를 자신 내부에서 호출한다. 필수요소는 아니나, 전달인자로 초깃값을 전달하지 않고 항상 같은 값으로 초기화가 가능하다.

convenience init(매개변수들) {
	초기화 구문
}
  1. 자식클래스의 지정 이니셜라이저는 부모클래스의 지정 이니셜라이저를 반드시 호출해야한다.
  1. 편의 이니셜라이저는 자신을 정의한 클래스의 다른 이니셜라이저를 반드시 호출해야한다.
  1. 편의 이니셜라이저는 궁극적으로는 지정 이니셜라이저를 반드시 호출해야만한다.

2단계 초기화

클래스 초기화는 2단계를 거친다.

1단계는 클래스에 정의한 각각의 저장 프로퍼티에 초깃값이 할당된다. 모든 저장 프로퍼티의 초기 상태가 결정되면 2단계로 돌입해 저장 프로퍼티들을 사용자 정의할 기회를 얻는다.

2단계는 프로퍼티를 초기화하기 전에 프로퍼티 값에 접근하는 것을 막아 초기화를 안전하게 할 수 있게한다.

이니셜라이저 상속 및 재정의

기본적으로 이니셜라이저는 부모클래스의 이니셜라이저를 상속받지 않는다.
부모클래스와 동일한 지정 이니셜라이저를 자식클래스에서 구현해주려면 override를 사용해 재정의 해주면 된다.자식클래스의 편의 이니셜라이저가 부모클래스의 지정 이니셜라이저를 재정의하는 경우에도 같다.

부모클래스의 편의 이니셜라이저와 동일한 이니셜라이저를 자식클래스에 구현할때는 override를 붙이지 않는다. 그 이유는 자식클래스에서 부모클래스의 편의 이니셜라이저는 절대로 호출할 수 없기 때문이다.

class Person{
	var name: String
    var age: Int
    
    init(name: String, age: int) {
    	self.name = name
        self.age = age
    }
    convenience init(name: String) {
    	self.init(name: name, age: 0)
    }
}

class Student: Person {
    var major: String
    
    override init(name:String, age: Int) {             //부모 클래스의 이니셜라이저를 상속받음
   		self.major = "Swift"
        super.init(name: name, age: age)
    }
    
    convenience init(name: String) {         //부모 클래스에서 정의한 편의 이니셜라이저와 동일한 편의 이니셜라이저를 정의 override 생략
    	self.init(name: name, age: 7)
    }
}

이니셜라이저 자동 상속

이니셜라이저는 부모클래스의 이니셜라이저를 상속받지 않는다. 그러나 조건에 부합한다면 자동으로 상속된다.

조건

  1. 자식클래스에서 별도의 지정 이니셜라이저를 구현하지 않는다면, 부모클래스의 지정 이니셜라이저가 자동으로 상속된다.
  1. 1 에 따라 자동으로 상속받은 경우 또는 부모클래스의 지정 이니셜라이저를 모두 재정의하여 부모클래스와 동일한 지정 이니셜라이저를 모두 사용할 수 있는 상황이라면 부모클래스의 편의 이니셜라이저가 모두 자동 상속된다. (자식클래스의 편의 이니셜라이저는 아무런 영향을 주지 못한다.)

요구 이니셜라이저

required 수식어를 클래스의 이니셜라이저 앞에 명시해주면 이 클래스를 상속받은 자식클래스에서 반드시 해당 이니셜라이저를 구현해주어야 한다.

  • 상속받을때 반드시 재정의해야 하는 이니셜라이저 앞에 required 수식어를 붙여준다.
  • 자식클래스에서 요구 이니셜라이저를 재정의할때는 override대신 required 수식어를 사용한다.
class Person {
	var name: String       //요구 이니셜라이저
    required init() {
    	self.name = "Unknown"
        }
}

class Student: Person {           //요구 이니셜라이저가 있었지만 위 조건 1에 부합하여 지정이니셜라이저를 자동 상속받음. 지정이니셜라이저가 존재했을경우 요구 이니셜라이저를 구현해주어야 했음.
	var major: String = "Unknown"
}

부모클래스에서 요구 이니셜라이저가 아니었더라도 자식 클래스에서 요구 이니셜라이저로 변경가능하고(required override), 편의 이니셜라이저 또한 요구 이니셜라이저로 변경가능하다.(required convienience)

0개의 댓글