• [Swift]⭐️클래스의 상속과 초기화⭐️

    2024. 2. 16.

    by. 멋진개발자

    클래스의 상속과 초기화

    1. 상속의 기본개념
      1. 클래스의 상속
      2. 메서드의 재정의(Override)
      3. 메모리 구조를 통한 이해
    2. 초기화의 과정과 생성자
      1. 초기화와 생성자
      2. 생성자

     

     

    1. 상속의 기본개념

    상속 📚

    🔨성격이 비슷한 타입을 새로만드는것

    • 데이터를 추가하거나
    • 기능을 변형시켜서 사용하거나

    ⇒ 한 클래스의 속성과 메서드를 다른 클래스가 받아들이는 것

    상속받은 클래스를 ‘하위 클래스’라고 하고, 상속해주는 클래스를 ‘상위 클래스’라 합니다.

     

     

    1) 클래스의 상속

    class SuperClass {
        var name = "Super Class"
        func superFunc() {
            print("This is Super Class function.")
        }
    }
    
    class SubClass: SuperClass {
    		// name
        var subName = "Sub Class"
    }
    
    * 위에서 SubClass는 SuperClass를 상속받았기 때문에 SuperClass의 속성과 메서드를 사용할 수 있다.

     

    📚 상속은 클래스, 프로토콜 등에서 가능하다 열겨형, 구조체는 상속이 불가능하다 스위프트의 클래스는 다중상속을 지원하지 않는다(단일상속)

     

    하위 클래스 (Subclassing)

    📚 하위 클래스는 기존 클래스를 기반으로 새로운 클래스를 만드는 작업 하위 클래스는 기존 클래스의 특성을 상속하므로 수정할 수 있고, 새로운 특성도 추가할 수 있다.

     

    서브클래스는 슈퍼클래스를 가지고 있음을 나타내기 위해 슈퍼클래스 이름 앞에 서브클래스 이름, :콜론으로 분리

    class SubClass: SuperClass {
    	// 서브클래스 정의하는 부분
    }

     

    2) 메서드의 재정의(Overriding)

    📚 하위 클래스는 상위 클래스에서 상속할 인스턴스 메서드, 타입 메서드, 인스턴스 프로퍼티, 타입 프로퍼티, 또는 서브 스크립트 자체 사용자 구현을 제공할 수 있습니다. 이것을 재정의 (overriding) 라고 합니다. 상속될 특성을 재정의 하려면 재정의 할 정의 앞에 override 키워드를 추가합니다.

     

    기본형태

    class SuperClass {
    	// 저장속성
    	var aData = 0
    	
    	// 메서드(계산속성)
    	func superFunc() {
    		print("superClass")
    	}
    }
    
    
    class SubClass: SuperClass {
    
    		override var aData = 3 // x 불가능 => 저장속성 재정의x
    
        override func superFunc() { // 계산속성 재정의o
    				//super.superFunc()
            print("서브클래스 재정의 호출하기")
    
        }
    }
    
    * 상위구현을 기반으로 기능을 추가할때 사용 ( 호출의 순서를 바꿔도 가능하다 )
    * 저장속성을 계산속성(메서드)으로 재정의는 가능하다
    
    override var aData: Int {
    		get {
    			return 1
    		}
    		set {
    			super.aData = newData
    		}
    }

     

     

    🌱 final 키워드 상속오버라이딩제한하는 역할

    더보기

    클래스에서 final 키워드 사용

    클래스 선언 앞에 final 키워드를 붙이면, 그 클래스는 상속될 수 없습니다. 즉, 다른 클래스가 해당 클래스를 생속받아 새로운 하위 클래스를 만드는 것을 막을 수 있습니다.

    final class MyFinalClass {
        var name: String = "MyFinalClass"
    }
    
    * MyFincalClass는 상속받을 수 없는 클래스가 됩니다.

    메서드에서 final 키워드 사용

    메서드 선언 앞에 final 키워드를 붙이면, 그 메서드는 오버라이드될 수 없습니다. 즉, 하위 클래스에서 해당 메서드를 재정의 하는 것을 막습니다.

    class MyClass {
        final func myMethod() {
            print("This method can't be overridden.")
        }
    }

     

    3) 메모리 구조를 통한 이해

    (상속과 재정의 그리고 메모리구조)

    Swift에서 객체는 힙(Heap) 영역에 저장됩니다. 각 객체는 고유의 메모리 주소를 가지며, 이 주소는 스택(Stack) 영역에 저장됩니다. 이를 통해 객체의 레퍼런스를 관리할 수 있습니다. 이렇게 메모리를 효율적으로 관리하면서도, Swift는 ARC(Automatic Reference Counting) 메모리 관리 기법을 통해 메모리 누수를 방지합니다.
    ❓ ARC (Automatic Reference Counting)

    메모리 관리를 자동으로 처리하는 방식을 의미합니다.

    ARC는 클래스 인스턴스의 메모리 영역을 관리하는데 있어서 핵심적인 역할을 합니다. 인스턴스가 생성될 때, ARC는 그 인스턴스를 위한 메모리 공간을 할당합니다. 이후 해당 인스턴스에 더 이상 접근할 수 없을 때, ARC는 그 메모리 공간을 회수합니다. 이처럼 ARC는 개발자가 직접 메모리를 관리하는 수고를 덜어줍니다. 하지만 ARC도 참조 순환 문제, 즉 두 개 이상의 클래스 인스턴스가 서로를 강하게 참조하면서 메모리에서 해제되지 못하는 상황을 해결하지 못합니다. 이런 상황을 방지하기 위해 Swift는
    약한 참조(weak reference)와 미소유 참조(unowned reference) 같은 개념을 도입했습니다.

    한줄 요약 : “Swift의 지능적인 메모리 관리자"

     

    2. 초기화의 과정과 생성자

    1) 초기화(Initialization)

    Swift에서 초기화는 클래스, 구조체, 열거형 인스턴스를 사용하기 전에 준비 단계를 의미합니다. 각 ‘저장속성’ 에 대한 초기값을 설정하여 인스턴스를 사용 가능한 상태로 만드는 것

     

    • 함수의 구현이 특별한 키워드인 init으로 명명됨
    • 인스턴스를 생성 과정: 저장 속성에 대한 초기값을 설정하여 사용가능한 상태가 되는 것
    • 생성자 메서드 실행의 목적은, 모든 저장 속성 초기화를 통한 인스턴스 생성

     

    1. 이니셜라이저

    class Dog {
    	var name: String
    	var weight: Double
    	...
    
    	init(name: String, weight: Double) {
    		self.name = name
    		self.weight = weight
    	}
    ...
    }
    
    * init 키워드로 이니셜라이저를 선언합니다.

     

     

    2. 옵셔녈 선언 형태

    class Color {
    	var red: Double?
    	var blue: Double?
    }
    
    * 옵셔널로 기본값을 설정하면 초기화 할 때 nil 값을 갖는다. => 생성자가 없어도 된다
    
    ⛔️ let으로 선언하면 Error
    => let은 변형되지 않은 타입 red,blue는 nil 이외의 값을 가지지 못하기 때문

     

     

    3. 기본값을 주는 형태

    class Color {
    	var red: Double = 0.1
    	var blue: Double = 0.1
    }
    
    * 선언과 동시에 기본값을 넣어주며 초기화

     

     

    4. 멤버와이즈 이니셜라이저 (구조체의 특별한 생성자)

    모든 멤버에 관련된 생성자 ⇒ 멤버와이즈 이니셜라이저 구조체의 경우 초기화되지 않은 프로퍼티를 초기화 시킬 수 있도록 "자동으로" 제공하는 생성자
    struct Color {
    	var red: Double
    	var green: Double
    	var blue: Double
    }
    
    var color1 = Color(red: Dobule, green: Double, blue: Double)
    
    * 생성자를 구현하지 않아도 자동으로 생성해준다.

     

    2) 생성자

    생성자는 클래스, 구조체, 열거형 인스턴스가 생성될 때 호출되는 특별한 메서드입니다. Swift에서는 'init' 키워드를 사용해 생성자를 정의합니다.

     

    구조체에서 생성자

    struct Color {
    	let red, blue: Double
    
    init() {. // 기본 생성자, 기본값을 설정하면 자동으로 제공
    	self.init(red: 0.0, blue: 0.0)	
    }
    
    init(black: Double) {
    	self.init(red: black, blue: black)
    }
    
    init(red: Double, blue: Double){
    	self.red = red
    	self.blue = blue
    	}
    }

     

     

    클래스에서 생성자

    지정생성자, 편의생성자

     

    지정생성자(Designated Initializers)

    클래스의 모든 프로퍼티를 초기화 하는 생성자

    - 기본 init 생성자를 지정생성자라고 합니다. (기본적으로 사용하던 방식)

    class Human {
        let name: String
        let age: Int
        
        init(name: String) {
            self.name = name
            self.age = 10
        }
    }

     

     

    편의생성자(Convenience Initializers)

    모든 프로퍼티를 초기화 할 필요 없는 생성자로, 반드시 다른 초기화를 호출시켜야 한다. (서브개념의 생성자)

    - 모든속성을 초기화 할 필요가 없습니다.

    class Dog {
    	var name: String
    	var weight: Double
    
    	init(name: String, weight: Double) {
    		self.name = name
    		self.weight = weight
    	}
    
    	convenience init(name: String) { // name에는 보리
    		self(name: name, wegiht: 10.0)
    	}  // 항상 몸무게를 10으로 세팅 => 원래 지정생성자를 호출
    }
    
    var dog1 = Dong(name: "코코", weight: 10)
    
    var dog2 = Dog(name: "보리") // 이름만 입력하고도 생성
    dog2.weight // 10

     

     


     

     

    참고자료

    Swift 공식문서 - https://bbiguduk.gitbook.io/swift/language-guide-1/inheritance
    Swift 기초 문법 (정대리 ) - https://www.youtube.com/watch?v=gGVibd4ZkmE
    Swift 개인블로그 - https://babbab2.tistory.com/168

    댓글