iOS 9th Class

๐ฉบ ํ๋ก์ ํธ ๊ณํ์ โ MyBMI (์คํ ๋ฆฌ๋ณด๋ ๊ธฐ๋ฐ)
1๏ธโฃ ํ๋ก์ ํธ ๊ฐ์
- ์ฑ ์ด๋ฆ: MyBMI โ ๋์ ๊ฑด๊ฐ ์ง์
- ๊ฐ๋ฐ ํ๊ฒฝ:
- Xcode ์ต์ ๋ฒ์ (์: Xcode 16 ๊ธฐ์ค)
- iOS 17 ์ด์ ์ง์
- UIKit + Storyboard ๊ธฐ๋ฐ
- Swift ์ธ์ด ์ฌ์ฉ
- ๋ชฉํ:
์คํ ๋ฆฌ๋ณด๋๋ฅผ ์ด์ฉํด UI๋ฅผ ์ง๊ด์ ์ผ๋ก ๊ตฌ์ฑํ๊ณ , ๊ฐ๋จํ BMI ๊ณ์ฐ๊ณผ ์ฒด์ค ์ถ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ด๋ณด์ ์นํํ iOS ์ฑ ๊ฐ๋ฐ.
2๏ธโฃ ์ฑ์ ์ฃผ์ ๊ธฐ๋ฅ
| ๊ตฌ๋ถ | ๊ธฐ๋ฅ๋ช | ์ค๋ช |
|---|---|---|
| ๐ก ๊ธฐ๋ณธ ๊ณ์ฐ | BMI ๊ณ์ฐ | ํค(cm)์ ๋ชธ๋ฌด๊ฒ(kg) ์ ๋ ฅ โ BMI ๊ณ์ฐ ํ ๊ฒฐ๊ณผ ํ์ |
| โ๏ธ ๋จ์ ์ ํ | ๋จ์ ๋ณ๊ฒฝ ๋ฒํผ | kg/cm โ lbs/inch ์ ํ (Segmented Control ์ฌ์ฉ) |
| ๐จ ์๊ฐํ | BMI ๊ฒฐ๊ณผ ์์ ํ์ | BMI ๋ฒ์์ ๋ฐ๋ผ ๋ผ๋ฒจ ์์ ๋ณ๊ฒฝ (์: ์ ์=์ด๋ก, ๊ณผ์ฒด์ค=์ฃผํฉ) |
| ๐ ๊ธฐ๋ก | ์ฒด์ค ์ ์ฅ/๊ธฐ๋ก ๋ณด๊ธฐ | Core Data or UserDefaults๋ฅผ ์ด์ฉํด ์ ๋ ฅ ๊ธฐ๋ก ์ ์ฅ ํ TableView๋ก ๋ณด์ฌ์ฃผ๊ธฐ |
| ๐ ์๋ฆผ (์ ํ) | ๋ฆฌ๋ง์ธ๋ ๊ธฐ๋ฅ | UNUserNotificationCenter ์ฌ์ฉ โ ์ฒด์ค ์ ๋ ฅ ์๋ฆผ (๊ธฐ๋ณธ ๋๊ธฐ, ์ค์ ์์ ์ผ๊ธฐ ๊ฐ๋ฅ) |
| ๐ ๋ค๊ตญ์ด | ํ๊ตญ์ด/์์ด ์ง์ | Localizable.strings ํ์ฉ |
| โ๏ธ ์ค์ | ์ค์ ํ๋ฉด | ๋จ์ ์ ํ, ๋ฐ์ดํฐ ์ด๊ธฐํ, ์๋ฆผ ์ค์ ๋ฑ |
ํ๋ฉด ๊ตฌ์ฑ (Storyboard ๊ตฌ์กฐ)
โถ 1. ๋ฉ์ธ ํ๋ฉด โ BMI ๊ณ์ฐ๊ธฐ
- ViewController:
MainViewController - ๊ตฌ์ฑ ์์:
- UILabel: โ๋์ BMI ๊ณ์ฐ๊ธฐโ
- UITextField (2๊ฐ): ํค ์ ๋ ฅ, ๋ชธ๋ฌด๊ฒ ์ ๋ ฅ
- UISegmentedControl: ๋จ์ ์ ํ (cm/kg, inch/lbs)
- UIButton: โ๊ณ์ฐํ๊ธฐโ
- UILabel: ๊ฒฐ๊ณผ ํ์ (BMI ์์น + ์ํ)
- UIView (๊ฒ์ด์ง ์์์ฉ): BMI ์ํ์ ๋ฐ๋ผ ์์ ๋ณ๊ฒฝ
- UIButton: โ๊ธฐ๋ก ๋ณด๊ธฐ๋ก ์ด๋โ
๐ก ๋ก์ง ๊ฐ์
let height = Double(heightTextField.text ?? "") ?? 0)
let weight = Double(weightTextField.text ?? "") ?? 0
let bmi = weight / pow(height/100, 2resultLabel.text = String(format: "BMI: %.1f", bmi)
BMI ๋ฒ์์ ๋ฐ๋ผ ์์๊ณผ ๋ฌธ๊ตฌ๋ฅผ ๋ณ๊ฒฝ (์: <18.5 ์ ์ฒด์ค, 18.5~24.9 ์ ์ ๋ฑ)
โถ 2. ๊ธฐ๋ก ํ๋ฉด โ Weight Record
- ViewController:
RecordViewController - ๊ตฌ์ฑ ์์:
- UITableView: ๋ ์ง๋ณ ์ฒด์ค ํ์
- UIButton: โ์ ๊ธฐ๋ก ์ถ๊ฐโ
- Navigation Bar Title: โ์ฒด์ค ๊ธฐ๋กโ
๐ก ๋ฐ์ดํฐ ์ ์ฅ ๋ฐฉ์
- ์ด๋ณด์์ฉ:
UserDefaults์ฌ์ฉ
(์:UserDefaults.standard.set(records, forKey: "weightRecords")) - ์ถํ ํ์ฅ: Core Data๋ก ์ ํ ๊ฐ๋ฅ
โถ 3. ์ ๊ธฐ๋ก ์ถ๊ฐ ํ๋ฉด โ Add Record
- ViewController:
AddRecordViewController - ๊ตฌ์ฑ ์์:
- UITextField: ์ฒด์ค ์ ๋ ฅ
- UIDatePicker: ๋ ์ง ์ ํ
- UIButton: โ์ ์ฅํ๊ธฐโ
์ ์ฅ ์ UserDefaults ๋ฐฐ์ด์ ์ถ๊ฐ โ Record ํ๋ฉด์ ํ ์ด๋ธ๋ทฐ ๋ฆฌ๋ก๋
โถ 4. ์ค์ ํ๋ฉด โ Settings
- ViewController:
SettingsViewController - ๊ตฌ์ฑ ์์:
- UISwitch: ์๋ฆผ ์ผ๊ธฐ/๋๊ธฐ
- UIButton: ๋ฐ์ดํฐ ์ด๊ธฐํ
- UISegmentedControl: ๋จ์ ๋ณ๊ฒฝ
ํ๋ฉด ์ ํ ๊ตฌ์กฐ (Storyboard Segue)
MainViewController
โโ(Show segue)โ RecordViewController
โ โโ(Modal segue)โ AddRecordViewController
โโ(Tab or modal)โ SettingsViewController
- Navigation Controller๋ฅผ ๋ฃจํธ๋ก ์ฌ์ฉ
- Segue Identifier๋ก ๊ฐ ํ๋ฉด ์ ํ ์ ์ด
- โ๋์๊ฐ๊ธฐโ ๋ฒํผ์ ์๋ ์์ฑ๋จ
ํ์ผ ๊ตฌ์กฐ (ํ๋ก์ ํธ ํด๋ ๊ตฌ์กฐ ์์)
MyBMI/
โโ Models/ โ โโ BMIModel.swift
โ โโ RecordModel.swift
โโ ViewControllers/ โ โโ MainViewController.swift
โ โโ RecordViewController.swift
โ โโ AddRecordViewController.swift
โ โโ SettingsViewController.swift
โโ Storyboard/ โ โโ Main.storyboard
โโ Resources/ โ โโ Assets.xcassets
โ โโ Localizable.strings
โโ AppDelegate.swift
๊ฐ๋ฐ ๋จ๊ณ๋ณ ์ผ์ (์คํ ๋ฆฌ๋ณด๋ ๋ฒ์ )
| ๋จ๊ณ | ๊ธฐ๊ฐ | ์ฃผ์ ๋ด์ฉ |
|---|---|---|
| 1๋จ๊ณ | 1์ฃผ | Storyboard ํ๋ฉด ์ค๊ณ (Main, Record, Add, Settings) |
| 2๋จ๊ณ | 2์ฃผ | BMI ๊ณ์ฐ ๋ก์ง + ๋จ์ ๋ณํ ๊ธฐ๋ฅ ๊ตฌํ |
| 3๋จ๊ณ | 3์ฃผ | ๊ธฐ๋ก ์ ์ฅ (UserDefaults), ํ ์ด๋ธ๋ทฐ ๊ตฌํ |
| 4๋จ๊ณ | 4์ฃผ | ์๋ฆผ ๊ธฐ๋ฅ ๋ฐ ์ค์ ํ๋ฉด ์ถ๊ฐ |
| 5๋จ๊ณ | 5์ฃผ | UI ๊ฐ์ ๋ฐ ๋ฒ๊ทธ ์์ |
| 6๋จ๊ณ | 6์ฃผ | TestFlight ๋ฐฐํฌ ๋ฐ ์ฑ์คํ ์ด ๋ฑ๋ก ์ค๋น |
ํฅํ ํ์ฅ ์์ด๋์ด
- ๊ทธ๋ํ ์ถ๊ฐ (์:
Chartsํ๋ ์์ํฌ๋ก ์ฒด์ค ๋ณํ ๊ทธ๋ํ) - HealthKit ์ฐ๋ (์ฒด์ค ์๋ ์ ๋ ฅ)
- AI ์ถ์ฒ (BMI ๊ฒฐ๊ณผ ๊ธฐ๋ฐ ์ด๋/์๋จ ํ ์ ์)






{
// ์
๋ ฅ๊ฐ ๊ฒ์ฆ
guard let heightText = txtHeight.text,
let weightText = txtWeight.text,
!heightText.isEmpty,
!weightText.isEmpty else {
lblResult.text = "ํค์ ์ฒด์ค์ ์
๋ ฅํ์ธ์!"
return
}
// Double ๋ณํ ๊ฒ์ฆ
guard let height = Double(heightText),
let weight = Double(weightText) else {
lblResult.text = "์ซ์๋ก ์
๋ ฅํด์ฃผ์ธ์!"
return
}
// BMI ๊ณ์ฐ
let bmi = weight / pow(height * 0.01, 2)
let shortenedBmi = String(format: "%.1f", bmi)
// ํ์ ๊ณ์ฐ
let body: String
switch bmi {
case 40...:
body = "3๋จ๊ณ ๋น๋ง"
case 30..<40:
body = "2๋จ๊ณ ๋น๋ง"
case 25..<30:
body = "1๋จ๊ณ ๋น๋ง"
case 18.5..<25:
body = "์ ์"
default:
body = "์ ์ฒด์ค"
}
// ๊ฒฐ๊ณผ ํ์
lblResult.text = "BMI: \(shortenedBmi), ํ์ : \(body)"
print("BMI: \(shortenedBmi), ํ์ : \(body)")
} var color = UIColor.white
if bmi >= 40 {
color = UIColor(displayP3Red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
body = "3๋จ๊ณ ๋น๋ง"
} else if bmi >= 30 && bmi < 40 {
color = UIColor(displayP3Red: 1.0, green: 0.7, blue: 0.0, alpha: 1.0)
body = "2๋จ๊ณ ๋น๋ง"
} else if bmi >= 25 && bmi < 30 {
color = UIColor(displayP3Red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0)
body = "1๋จ๊ณ ๋น๋ง"
} else if bmi >= 18.5 && bmi < 25 {
color = UIColor(displayP3Red: 0.0, green: 0.8, blue: 0.0, alpha: 1.0)
body = "์ ์"
} else {
color = UIColor(displayP3Red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
body = "์ ์ฒด์ค"
}
print("BMI:\(shortenedBmi), ํ์ :\(body)")
lblResult.backgroundColor = color
lblResult.clipsToBounds = true
lblResult.layer.cornerRadius = 20
lblResult.text = "BMI:\(shortenedBmi), ํ์ :\(body)"


