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개의 댓글

관련 채용 정보