[TIL] 실패는 성공의 어머니라고 했다.. ( 업캐스팅과 다운캐스팅 )

EarthSea·2024년 3월 6일
0

✏️ TIL

목록 보기
2/2
post-thumbnail

오늘도 9시가 넘어서야 TIL을 작성하구 있네요..!

너무 집중이 안되서 커피 수혈을 조금 했는데..
심장이 쿵! 쾅! 쿵! 쾅! 과다 카페인 섭취를 한 거 같아요..
몸이 아주 무리데스네
그렇게 오늘 저녁은 패스입니다요..



다운캐스팅 Error

과제를 풀다가 다운 캐스팅을 사용해서 기깔나게 마무리하려고 했는데.. 반복적으로 생기는 오류!
대체 뭐가 문제인지 모르겠어서 구글링을 거쳐서 다운 캐스팅과 업 캐스팅부터 다시 공부합니다.



업캐스팅(Upcasting)과 다운캐스팅(Downcasting)

두 단어 모두 클래스의 상속과 관련된 용어로 부모클래스와 자식클래스 사이의 타입 변환을 위해 사용됩니다.

업캐스팅이란?
하위 클래스의 인스턴스를 상위 클래스 타입으로 변환하는 것

  • [하위 클래스의 인스턴스] as [상위 클래스]
  • 안전하게 진행할 수 있어 따로 검사가 필요하지 않다.

다운캐스팅이란?
상위 클래스의 인스턴스를 하위 클래스 타입으로 변환하는 것

다운캐스팅은 항상 안전하게 진행될 수 없기 때문에 오류가 생길 수도 있습니다. 옵셔널 바인딩을 하는 것과 같이 캐스팅하는 방법이 두 가지 존재합니다.

[ 첫번째 방법 ] as! (강제 다운 캐스트)

  • [상위 클래스의 인스턴스] as! [하위 클래스]
  • 강제로 업래핑을 하는 거다 보니 런타임 시점에서 다운 캐스트를 성공하지 못했다면 에러가 납니다.

[ 두번째 방법 ] as? (안전한 다운 캐스트)

  • [상위 클래스의 인스턴스] as? [하위 클래스]
  • 런타임 시점에서 다운 캐스팅을 진행하는데 성공하지 못했다면 nil을 반환
    -> 옵셔널 타입으로 지정해주어야함!

해결

제가 에러가 난 부분을 다시 확인해보니 저는 강제 다운 캐스트를 진행을 했는데 런타임 시점에서 성공하지 못해서 에러가 났습니다.

  • 클래스 선언부

    class AbstractOperation {
        func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return 0.0
        }
    }
    
    class AddOperation4: AbstractOperation {
        override func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return Double(firstNumber + secondNumber)
        }
    }
    
    class SubtractOperation4: AbstractOperation {
        override func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return Double(firstNumber - secondNumber)
        }
    }
    
    class MultiplyOperation4: AbstractOperation {
        override func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return Double(firstNumber * secondNumber)
        }
    }
    
    class DivideOperation4: AbstractOperation {
        override func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return Double(firstNumber) / Double(secondNumber)
        }
    }
    
    class ModulusOperation4: AbstractOperation {
        override func calculate(_ firstNumber: Int ,_ secondNumber: Int) -> Double {
            return Double(firstNumber % secondNumber)
        }
    }
  • 다운캐스팅하여 위의 클래스의 인스턴스를 활용하려는 클래스

    class Calculator4 {
    
        var firstNumber: Int = 0
        var secondNumber: Int = 0
        var op: Character?
    
        init(firstNumber: Int, secondNumber: Int, op: Character? = nil) {
            self.firstNumber = firstNumber
            self.secondNumber = secondNumber
            self.op = op
        }
    
        func calculate() -> Double {
    
            var operation = AbstractOperation()
    
            // 🚨Error
            if op == "+" { operation as! AddOperation4 }
            else if op == "-" { operation as! SubtractOperation4 }
            else if op == "/" { operation as! DivideOperation4 }
            else if op == "*" { operation as! MultiplyOperation4 }
            else if op == "%" { operation as! ModulusOperation4 }
            else { return 0.0 }
    
            return operation.calculate(firstNumber, secondNumber)
        }
    }
  • Calculator4의 인스턴스를 만들어 해당 메서드를 이용해 값 출력

    let calculator4 = Calculator4(firstNumber: 30, secondNumber: 6, op: "+")
    let addResult = calculator4.calculate()
    print("addResult : \(addResult)")

위의 코드는 addResult에서 " error: execution was interrupted, reason: signal sigabrt. the process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation. " 이런 에러가 나더라구요. 강제 다운 캐스팅에 실패했을 때 뜨는 에러라고 합니다.

우선 업캐스팅과 다운캐스팅을 공부하고 다시 봤더니 제가 난 오류는 단순히 다운 캐스팅때문에 난 오류가 아니더라구요.. 개념적으로 풀 수 없는 방법으로 풀려고 시도했더니 안되지..
그래도 혹시나 혹시나 가능할 수도 있으니 내일 튜텨님께 질문을 꼭 해봐야겠어요!

Calculator4의 calculate() 메서드를 이렇게 고쳤더니 해결이 되었습니다!

func calculate() -> Double {

// 		  🚨Error
//        var operation = AbstractOperation()
//        if op == "+" { operation as! AddOperation4 }
//        else if op == "-" { operation as! SubtractOperation4 }
//        else if op == "/" { operation as! DivideOperation4 }
//        else if op == "*" { operation as! MultiplyOperation4 }
//        else if op == "%" { operation as! ModulusOperation4 }
//        else { return 0.0 }
        
        guard let op = op else { return 0.0 }
        
        switch op {
        case "+" :
            return AddOperation4().calculate(firstNumber, secondNumber)
        case "-" :
            return SubtractOperation4().calculate(firstNumber, secondNumber)
        case "/" :
            return DivideOperation4().calculate(firstNumber, secondNumber)
        case "*" :
            return MultiplyOperation4().calculate(firstNumber, secondNumber)
        case "%" :
            return ModulusOperation4().calculate(firstNumber, secondNumber)
        default :
            print("계산기에 존재하지 않는 연산자입니다.")
            return 0.0
        }
    }



[ 내일 해결해야 할 문제 ]
❎ 한가지의 변수에 부모 클래스의 인스턴스를 대입하고, 그 변수를 자식 클래스로 다운캐스팅하여 메서드를 사용하려고 할 때, 경우에 따라 다른 다운 캐스팅을 하여 진행하면 안되는지.. 안된다면 왜 안되는지..!!!!


참고한 블로그 📄

https://babbab2.tistory.com/127

profile
I'm Junior iOS developer 배지해.

0개의 댓글