Swift TIL(69)-MVC로 리팩토링, 옵셔널이 담기는 경우 정리, 모델에서 속성을 접근하는 방법

웰디(Well-D)·2023년 11월 4일
0

Sweet & Soft, SWIFT

목록 보기
68/76

BMI 앱 리팩토링 MVC 패턴을 통해 진행

리팩토링 내용

  1. M-V-C 로 폴더 및 파일 분리, Models 폴더 내 BMICalculatorManager 파일 생성
  2. 기존에 bmiNumber, adviceString, bmiLabelColor 등으로 나뉘어진 bmi정보를 구조체로 묶어서 전달, 모델에서 계산, 다시 받아오고 second 뷰에서도 구조체로 받아서 묶어서 그리기

오늘 내가 좀 더 배우고 고민한 부분

옵셔널타입이 담길때의 올바른 해석

// 계산된 bmi 를 받아서 그리는 두번째 화면의 코드 
// 참고로 bmi 의 타입은 BMI?이다. 
// BMI 구조체에는 value, advice, matchColor 속성이 있다. 
         guard let bmi = bmi else { return }
        //💡 어차피 양쪽 모두 옵셔널 이므로 옵셔널 체이닝 불필요한 경우(바로 밑 코드한줄)
         bmiNumberLabel.text = String(bmi.value)
        // bmi 자체는 옵셔널이 아니지만 String 화 하면서 옵셔널이 됨 => bmi.value 는 옵셔널이 아니지만 String(bmi.value)는 옵셔널임
        
        // 밑에는 왼쪽은 옵셔널, 오른쪽은 옵셔널이 아닌코드이므로 담을 수 있음
         adviceLabel.text = bmi.advice
         bmiNumberLabel.backgroundColor = bmi.matchColor

강의를 들을때 헷갈려서 내가 이해한 바로 위의 코드를 토대로 옵셔널이 담기는 경우를 정리해보았다.

옵셔널일때 담기는 케이스 정리

1. 왼쪽 오른쪽 모두 옵셔널 타입이라서 담기는 경우

bmiNumberLabel.text = String(bmi.value)
=> bmi.value 는 옵셔널이 아니지만 String 생성자 혹은 "()"와 같은 string Interpolation으로 값을 변경하면 옵셔널 string 즉 String? 타입이 된다.

2. 왼쪽은 String? 오른쪽은 String 으로 포함관계가 가능하여 담기는 경우

adviceLabel.text = bmi.advice
bmiNumberLabel.backgroundColor = bmi.matchColor
=> 다음의 경우 왼쪽은 옵셔널, 오른쪽은 옵셔널이 아닌코드이므로 담을 수 있음

모델의 private 속성 접근제어와 메서드를 통한 간접 접근 설계

대부분의 경우 private으로 모델의 속성은 접근제어를 걸어주고, 이때 만약 다른 화면에서(실제 controller 을 의미) 해당 속성의 접근이 필요시 메서드로 접근할 수 있도록 설계한다

//모델인 BMICalculatorManager구조체 내부  
    // private 으로 접근제어 함
    // 외부에서 바로 접근 불가능 
    
    private var bmi: BMI?
     	
    // 메서드를 통해 bmi 접근 가능        
    mutating func getBMIResult(height: String, weight: String) -> BMI {
    calculateBMI(height: height, weight: weight)
    return bmi ?? BMI(value: 0.0, matchColor: .white, advice: "문제발생")

   // 기타 등등 코드
   
}

이렇게 속성 자체는 private 선언을 해주고 대신 BMI를 리턴해주는 매서드를 작성함으로써 해당 매서드를 통해 간접적으로 bmi 를 받을 수 있도록 한다

해당 bmi를 받아쓰는 예시

//viewController 클래스 내부 
// 참고 : 버튼이 눌리면 shouldPerformSegue => prepare 까지 자동호출됨 

var bmiManager = BMICalculatorManager()
    
override func prepare(<for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toSecondVC" {
            let secondVC = segue.destination as! SecondViewController
            guard let height = heightTextField.text,
                  let weight = weightTextField.text else { return }
            // bmiManager.bmi => 불가능함 (private)
            // bmi에 간접적으로 접근할 수 있는 매서드를 호출하고 결과값을 담는 역할 (직접적으로 접근하는 것은 private 제어걸려서 불가능)
            secondVC.bmi = bmiManager.getBMIResult(height: height, weight: weight)
            
        }

bmiManager.bmi => 불가능함 (private)
bmiManager.getBMIResult(height: height, weight: weight)
=> 다음과 같이 bmi를 리턴하는 모델 내부 메서드를 사용하여 간접적으로 bmi 값을 받아와야함

profile
Wellness 잘사는 것에 진심인 웰디입니다. 여러분의 몸과 마음, 통장의 건강을 수호하고싶어요. 느리더라도, 꾸준히

0개의 댓글