[iOS] BMI 앱 만들기 1주

2025. 11. 11. 16:43·iOS


목차

  1. 개요
  2. 화면 구성 & 아키텍처 개요
  3. 핵심 코드 라인-by-라인 해설
  4. 입력 처리(로케일/포맷) 설계 포인트
  5. BMI 계산 흐름과 결과 표시
  6. UX 디테일(키보드, 포커스, 터치 처리)
  7. 확장: BMI 분류 버튼 액션 구현 예시
  8. 실습 체크리스트 & 흔한 오류(KVC, 아울렛 연결)
  9. 마무리 팁

1) 개요

이 글은 아래 ViewController 코드가 어떤 책임을 갖고, 어떤 흐름으로 동작하며, 어디를 확장하면 되는지를 초보 개발자 관점에서 차근차근 설명합니다.
작성 언어는 Swift + UIKit, 입력은 UITextField, 출력은 UILabel이며 BMI 계산은 별도 모델(BMI)을 호출하는 구조를 가정합니다.


2) 화면 구성 & 아키텍처 개요

  • 입력 필드 2개: txtHeight(키 cm), txtWeight(몸무게 kg)
  • 결과 라벨: lblResult
  • 버튼 2개(가정): “계산”(calcBmi)과 “분류”(classificationForBMI)
  • 아키텍처 감각:
    • Controller는 사용자 입력을 검증하고, **도메인 로직(BMI 계산)**은 BMI 타입에 위임합니다.
    • 이렇게 분리하면 테스트가 쉬워지고, 유지보수성이 좋아집니다.

3) 핵심 코드 라인-by-라인 해설

class ViewController: UIViewController, UITextFieldDelegate {
  • UIViewController 상속 + UITextFieldDelegate 채택 → 텍스트필드 리턴키 동작 등 입력 제어 가능.
@IBOutlet weak var txtHeight: UITextField!
@IBOutlet weak var txtWeight: UITextField!
@IBOutlet weak var lblResult: UILabel!
  • 스토리보드와 연결되는 아울렛. Xcode Interface Builder에서 ViewController에 드래그로 연결해야 합니다.
    • 연결 불일치 시 런타임에 KVC 에러(예: “not key value coding-compliant”)가 발생합니다. (8장 참고)
override func viewDidLoad() {
    super.viewDidLoad()
    txtHeight.placeholder = "키(cm)를 입력하세요"
    txtWeight.placeholder = "몸무게(kg)를 입력하세요"
    
    txtHeight.keyboardType = .decimalPad
    txtWeight.keyboardType = .decimalPad
    
    txtHeight.delegate = self
    txtWeight.delegate = self
    
    lblResult.text = "키와 몸무게를 입력한 뒤 계산 버튼을 눌러주세요"
}
  • 초기 UI 세팅:
    • placeholder로 입력 가이드 제공.
    • decimalPad 키패드 → 숫자/소수점만 입력되도록 UX 개선.
    • delegate 지정 → 리턴키 이동/계산 자동 트리거 가능.
    • 결과 라벨에 초기 안내 문구 세팅.
@IBAction func calcBmi(_ sender: UIButton) {
    view.endEditing(true)
  • 키보드 내리기: 버튼 탭 시 편집 종료로 키보드 숨김.
    guard
        let h = parseNumber(from: txtHeight.text),
        let w = parseNumber(from: txtWeight.text),
        h > 0, w > 0
    else {
        lblResult.text = "유효한 키(cm)와 몸무게(kg)를 입력하세요"
        return
    }
  • 입력 검증: 숫자 파싱 실패 또는 0 이하 값이면 즉시 사용자에게 피드백.
  • parseNumber로 공백 제거, 쉼표→점 치환 등 유연한 입력 허용.
    let bmi = BMI(weight: w, height: h)
    lblResult.text = bmi.calcBMI()
}
  • **도메인 객체(BMI)**에 계산 위임 → 컨트롤러가 비즈니스 로직을 직접 갖지 않음(좋은 분리).
private func parseNumber(from text: String?) -> Double? {
    let cleaned = (text ?? "")
        .replacingOccurrences(of: " ", with: "")
        .replacingOccurrences(of: ",", with: ".")
    return Double(cleaned)
}
  • 문자열 전처리로 파싱 내구성 강화:
    • 공백 제거
    • 소수 구분자 **, → .**로 통일(일부 로케일 사용자가 쉼표를 소수점으로 입력하는 상황 대응)
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if textField == txtHeight {
        txtWeight.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
        calcBmi(UIButton())
    }
    return true
}
  • 리턴키 UX:
    • 키 입력 흐름: 키 → 몸무게로 포커스 이동
    • 몸무게에서 리턴키: 포커스 내리고 바로 계산 호출(빠른 입력 흐름)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
}
  • 화면 빈 공간 터치 시 키보드 내려가기: 모바일에서 필수 UX 디테일.
@IBAction func classificationForBMI(_ sender: UIButton) {
    
}
  • 확장 포인트: 계산된 BMI 값을 **범주(저체중/정상/과체중/비만)**로 보여줄 버튼 액션. 아래 7장에서 예시 제공.

4) 입력 처리(로케일/포맷) 설계 포인트

  • 사용자가 170,5처럼 쉼표 소수점을 입력할 수 있습니다.
  • parseNumber가 쉼표를 점으로 바꿔 Double 파싱을 시도하므로 국내/유럽권 혼용 입력에 꽤 관대합니다.
  • 더 정교하게 하려면 NumberFormatter를 쓰고 현재 로케일(Locale.current)을 반영하는 것도 좋습니다.

5) BMI 계산 흐름과 결과 표시

  • 컨트롤러는 입력 검증과 흐름 제어만 담당하고, 실제 계산은 BMI 타입에 맡깁니다.
  • 예시 BMI 타입(참고용):
struct BMI {
    let weight: Double   // kg
    let height: Double   // cm

    func calcBMI() -> String {
        let m = height / 100.0
        guard m > 0 else { return "키가 올바르지 않습니다." }
        let value = weight / (m * m)
        let rounded = (value * 10).rounded() / 10  // 소수점 1자리
        return "BMI: \(rounded)"
    }

    func category() -> String {
        let m = height / 100.0
        guard m > 0 else { return "키가 올바르지 않습니다." }
        let v = weight / (m * m)
        switch v {
        case ..<18.5: return "저체중"
        case 18.5..<23: return "정상(대한비만학회 기준)"
        case 23..<25: return "과체중"
        case 25..<30: return "비만(1단계)"
        default: return "고도비만(2단계+)"
        }
    }
}

포인트: 아시아(대한비만학회) 기준은 서구 기준(정상 18.5~25)과 다릅니다. 사용 목적에 맞는 기준을 명시하세요.


6) UX 디테일(키보드, 포커스, 터치 처리)

  • decimalPad로 잘못된 문자 입력을 사전 차단 → 에러 메시지 빈도 감소.
  • textFieldShouldReturn으로 빠른 폼 이동/자동 계산 → 입력 흐름 매끄러움.
  • touchesBegan으로 언제든 화면 탭 → 키보드 숨김 → 답답함 해소.

7) 확장: BMI 분류 버튼 액션 구현 예시

현재 classificationForBMI는 비어 있으므로 다음처럼 구현할 수 있습니다.

@IBAction func classificationForBMI(_ sender: UIButton) {
    view.endEditing(true)

    guard
        let h = parseNumber(from: txtHeight.text),
        let w = parseNumber(from: txtWeight.text),
        h > 0, w > 0
    else {
        lblResult.text = "유효한 키(cm)와 몸무게(kg)를 입력하세요"
        return
    }

    let bmi = BMI(weight: w, height: h)
    let resultText = "\(bmi.calcBMI())\n분류: \(bmi.category())"
    lblResult.text = resultText
}

적용 방식: “계산” 버튼은 숫자만 표시, “분류” 버튼은 숫자 + 카테고리 표시처럼 역할을 분리하면 사용자에게 더 명확합니다.


8) 실습 체크리스트 & 흔한 오류(KVC, 아울렛 연결)

✅ 체크리스트

  • 스토리보드에서 ViewController의 Class가 실제 파일의 클래스명과 일치하는가?
  • txtHeight, txtWeight, lblResult 아울렛 연결이 모두 되어 있는가?
  • “계산”, “분류” 버튼의 IBAction 연결이 맞는가?
  • 각 텍스트필드의 Keyboard Type은 .decimalPad인가?
  • 탭/리턴키 동작이 의도대로 포커스를 이동/계산하는가?
  • 비정상 입력(공백, 음수, 0, 문자) 시 에러 메시지가 잘 표시되는가?

❗흔한 오류: KVC(Key-Value Coding) 불일치

  • 증상: 앱 실행 직후 크래시 +
    this class is not key value coding-compliant for the key ...
  • 원인: 스토리보드에서 연결된 아울렛/액션의 이름 또는 타입이 변경/삭제되었는데, 연결을 갱신하지 않음.
  • 해결:
    1. 스토리보드에서 해당 ViewController 선택
    2. Connections Inspector 탭에서 ⚠️표시된 연결 삭제
    3. 실제 코드의 @IBOutlet / @IBAction 이름과 타입을 확인하고 다시 연결
    4. 클래스명, 모듈 설정도 올바른지 확인

9) 마무리 팁

  • 컨트롤러는 “흐름/검증”, 모델은 “계산/규칙”: 역할을 나누면 코드가 깨끗해집니다.
  • 입력 전처리는 지금처럼 단순 문자열 치환으로 시작하고, 필요 시 NumberFormatter + 로케일 대응으로 확장하세요.
  • BMI 기준은 사용자에게 공지(대한비만학회 vs WHO 등). 혼동을 줄이고 신뢰성을 높입니다.
  • 테스트는 경계값(예: 18.5, 23, 25, 30)에 특히 집중하세요.

'iOS' 카테고리의 다른 글

[iOS]BMI 앱 만들기 3주차  (0) 2025.11.25
[iOS]BMI 앱 만들기 2주  (0) 2025.11.18
[iOS]10주차 이후 — BMI 판정 / 동영상 재생 / 웹뷰 앱 만들기  (0) 2025.11.04
[iOS]9 주차 — Xcode로 간단한 앱 개발 정리  (0) 2025.10.28
[iOS] 7주차 Swift 문법 클래스(Class), Failable Initializer, 상속  (1) 2025.10.14
'iOS' 카테고리의 다른 글
  • [iOS]BMI 앱 만들기 3주차
  • [iOS]BMI 앱 만들기 2주
  • [iOS]10주차 이후 — BMI 판정 / 동영상 재생 / 웹뷰 앱 만들기
  • [iOS]9 주차 — Xcode로 간단한 앱 개발 정리
harang Lee
harang Lee
404...
  • harang Lee
    SkyWith628
    harang Lee
  • 전체
    오늘
    어제
    • 분류 전체보기 (126)
      • AI (55)
      • C (20)
      • C++ (23)
      • iOS (18)
      • Python (1)
      • AWS (4)
      • Git (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    C프로그래밍
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
harang Lee
[iOS] BMI 앱 만들기 1주
상단으로

티스토리툴바