Class 상속에서 초기화 문제 해결 🚨

jeongmuyamette·2025년 7월 26일

TIL

목록 보기
71/72
post-thumbnail

❌ 문제점 분석

현재 코드가 오류가 나는 이유를 설명해드릴게요!

class Dog {
    var name: String
    var breed: String
    
    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

class Collie: Dog {
    // ❌ 여기서 오류 발생!
}

🔍 오류 원인

1. 부모 클래스의 초기화 메서드 호출 누락

  • Dog 클래스에는 designated initializer가 있음
  • CollieDog를 상속받았지만, 부모의 초기화 메서드를 호출하지 않음
  • Swift는 모든 저장 프로퍼티가 초기화되어야 한다는 규칙이 있음

2. Swift 초기화 규칙

Swift의 초기화 규칙:
1. 모든 저장 프로퍼티는 초기화되어야 함
2. 자식 클래스는 부모 클래스의 초기화 메서드를 호출해야 함
3. designated initializer가 있으면 반드시 호출해야 함

✅ 해결 방법들

방법 1: 자식 클래스에서 초기화 메서드 구현

class Dog {
    var name: String
    var breed: String
    
    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

class Collie: Dog {
    // ✅ 부모 클래스의 초기화 메서드 호출
    init(name: String) {
        super.init(name: name, breed: "Collie")
    }
}

// 사용 예시
let myCollie = Collie(name: "래시")
print("\(myCollie.name)\(myCollie.breed) 품종입니다.")
// 출력: 래시는 Collie 품종입니다.

방법 2: 자식 클래스에서 추가 프로퍼티가 있는 경우

class Dog {
    var name: String
    var breed: String
    
    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

class Collie: Dog {
    var intelligence: Int  // 콜리 특유의 지능 점수
    
    init(name: String, intelligence: Int) {
        self.intelligence = intelligence  // 1. 자신의 프로퍼티 먼저 초기화
        super.init(name: name, breed: "Collie")  // 2. 부모 초기화 호출
    }
}

// 사용 예시
let smartCollie = Collie(name: "래시", intelligence: 95)
print("\(smartCollie.name)의 지능: \(smartCollie.intelligence)점")

방법 3: 여러 초기화 메서드 제공

class Dog {
    var name: String
    var breed: String
    
    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

class Collie: Dog {
    var intelligence: Int
    
    // 기본 초기화 (지능 점수 기본값)
    init(name: String) {
        self.intelligence = 80  // 기본 지능 점수
        super.init(name: name, breed: "Collie")
    }
    
    // 상세 초기화 (지능 점수 직접 설정)
    init(name: String, intelligence: Int) {
        self.intelligence = intelligence
        super.init(name: name, breed: "Collie")
    }
    
    // 완전 커스텀 초기화
    init(name: String, breed: String, intelligence: Int) {
        self.intelligence = intelligence
        super.init(name: name, breed: breed)
    }
}

// 다양한 사용 방법
let collie1 = Collie(name: "래시")                    // 기본 지능
let collie2 = Collie(name: "보더", intelligence: 95)   // 지능 설정
let collie3 = Collie(name: "믹스", breed: "Border Collie", intelligence: 90)  // 완전 커스텀

🎯 초기화 순서 이해하기

class Dog {
    var name: String
    var breed: String
    
    init(name: String, breed: String) {
        print("🐕 Dog 초기화: \(name), \(breed)")
        self.name = name
        self.breed = breed
    }
}

class Collie: Dog {
    var intelligence: Int
    
    init(name: String, intelligence: Int) {
        print("🧠 Collie 프로퍼티 초기화 시작")
        self.intelligence = intelligence  // 1️⃣ 자신의 프로퍼티 먼저
        
        print("📞 부모 클래스 초기화 호출")
        super.init(name: name, breed: "Collie")  // 2️⃣ 부모 초기화
        
        print("✅ Collie 초기화 완료")
    }
}

// 테스트
let collie = Collie(name: "래시", intelligence: 95)

출력 결과:

🧠 Collie 프로퍼티 초기화 시작
📞 부모 클래스 초기화 호출
🐕 Dog 초기화: 래시, Collie
✅ Collie 초기화 완료

💡 핵심 포인트

초기화 규칙 요약:

  1. 자식의 저장 프로퍼티 먼저 초기화
  2. 그 다음 super.init() 호출
  3. 부모의 프로퍼티 수정은 super.init() 이후에만 가능

왜 이런 규칙이 있을까?

  • 메모리 안전성: 모든 프로퍼티가 초기화되어야 안전
  • 상속 체계 보장: 부모-자식 관계가 올바르게 설정
  • 런타임 오류 방지: 초기화되지 않은 프로퍼티 접근 방지

0개의 댓글